1、多线程-同步代码块:synchronized
当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步。
如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码。
synchronized关键字加上一个锁对象就可以同步代码,这个锁对象可以是任意的一个对象,只要求是同一个就行。
例如:
class Printer {
Demo d = new Demo();
public static void print1() {
synchronized(d){
System.out.print(“你”);
System.out.print(“好”);
System.out.print(“呀”);
System.out.print(“\r\n”);
}
}
public static void print2() {
synchronized(d){
System.out.print(“C”);
System.out.print(“S”);
System.out.print(“D”);
System.out.print(“N”);
System.out.print(“\r\n”);
}
}
}
class Demo{ //创建一个任意的class,用来做锁对象
public Demo(){}
}
现在在主函数里面创建2条线程执行:如果不加synchronized(d),可能输出print1 和print2就会出现乱序的问题(你好呀CS)。
final Printer p = new Printer();
new Thread(){
public void run(){ //重写Thread类里面的run方法
p.print1();
}
}.start(); //启动一个线程
new Thread(){
public void run(){ //重写Thread类里面的run方法
p.print1();
}
}.start(); //启动第二个线程
2、多线程-同步方法:synchronized
使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
例如:
class Printer {
public static synchronized void print1() {
//这里的锁对象就是Printer.class(字节码对象) ,锁对象可以是任意的,但必须是同一把锁
System.out.print(“你”);
System.out.print(“好”);
System.out.print(“呀”);
System.out.print(“\r\n”);
}
public static void print2() {
synchronized(Printer.class){
//这里使用Printer.class(字节码对象)对象作为锁对象
System.out.print(“C”);
System.out.print(“S”);
System.out.print(“D”);
System.out.print(“N”);
System.out.print(“\r\n”);
}
}
}
注意:
非静态同步函数的锁是:this (因为创建的对象是同一个,此时的this就代表new的那个对象)
静态static的同步函数的锁是:字节码对象(因为使用 类名.方法 调用 ,类名是同一个)
3、多线程-线程安全:
多线程并发操作同一数据时, 就有可能出现线程安全问题,使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
class TicketsSeller extends Thread {
private static int tickets = 100;//定义一个私有静态变量
static Object obj = new Object();//定义一个锁对象
public TicketsSeller() {
super();
}
public TicketsSeller(String name) {
super(name);
}
public void run() {
while(true) {
synchronized(obj) {//如果没有锁的话,就可能出现多个线程同时操作了tickets这个变量,导致if多次判断0后,还进行了–操作,导致负号票出现
if(tickets <= 0)
break;
System.out.println(getName() + “…这是第” + tickets– + “号票”);
}
}
}
}
//伪代码,创建4个线程调用
t1.start();
t2.start();
t3.start();
t4.start();
3、多线程-死锁:
多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁,所以尽量不要嵌套使用。
private static String s1 = “left”;//定义一个锁对象s1
private static String s2 = “right”;//定义一个锁对象s2
public static void main(String[] args) {
new Thread() {
public void run() {
while(true) {
synchronized(s1) {
System.out.println(getName() + “get” + s1 + “wait” + s2);
synchronized(s2) { //有可能执行到这个地方的时候,s2被下面线程使用,未释放,就拿不到s2了
System.out.println(getName() + “get” + s2 + “OK”);
}
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
synchronized(s2) {
System.out.println(getName() + “get” + s2 + “wait” + s1);
synchronized(s1) { //执行到这个地方,s1被上面线程使用,未释放,线程就一直卡在这了
System.out.println(getName() + “get” + s1 + “OK”);
}
}
}
}
}.start();
}
4、多线程-常用线程安全类有哪些:看源码,有synchronized修饰的方法或代码块就是线程安全的
Vector是线程安全的,ArrayList是线程不安全的
StringBuffer是线程安全的,StringBuilder是线程不安全的
Hashtable是线程安全的,HashMap是线程不安全的