主要内容:
- 线程同步及线程同步可能出现的问题
- 对象互斥锁,synchronized关键字
- 死锁
- 线程锁定一个对象后,另一个线程访问对象对应类中其他方法的不同情况
线程同步:多个线程访问同一资源
若两个线程对同一共享资源并发访问时可能会出现问题。eg:银行取款
/* * 线程同步的例子 * */ public class Test { public static void main(String[] args) { //创建两个线程并执行同一条语句 Run r=new Run(); Thread t1=new Thread(r,"t1"); Thread t2=new Thread(r,"t2"); t1.start(); t2.start(); } } class Run implements Runnable{ Timer t=new Timer(); //两个开始的线程调用同一个类中的方法 public void run(){ t.add(Thread.currentThread().getName()); } } class Timer{ int num=0; //计数 Thread t=new Thread(); //当第一个线程执行完计数,睡眠1ms时,第二个线程开始执行计数并睡眠1ms,然后第一个线程打印, //接着第二个线程打印,打印时计数以累加到2. public void add(String ThreadName){ num++; try { t.sleep(1); } catch (InterruptedException e) { } System.out.println(ThreadName+"第"+num+"次执行"); } }
对象互斥锁:每个对象对应一个称为互斥锁的标记,这个标记保证在任何时刻,只有一个线程访问该对象。
当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
关键字synchronized,在执行方法的过程中锁定当前对象。
synchronized关键字是不能继承的.
/* * 避免线程同步。(synchronized方法 ) */ public class Test { public static void main(String[] args) { //创建两个线程并执行同一条语句 Run r=new Run(); Thread t1=new Thread(r,"t1"); Thread t2=new Thread(r,"t2"); t1.start(); t2.start(); } } class Run implements Runnable{ Timer t=new Timer(); //两个开始的线程调用同一个类中的方法 public void run(){ t.add(Thread.currentThread().getName()); } } class Timer{ int num=0; //计数 Thread t=new Thread(); public synchronized void add(String ThreadName){ //通过关键字synchronized,在执行方法的过程中锁定当前对象。 // synchronized (this){ num++; try { t.sleep(1); } catch (InterruptedException e) { } System.out.println(ThreadName+"第"+num+"次执行"); //} } }
/* * 避免线程同步。(synchronized块) */ public class Test { public static void main(String[] args) { //创建两个线程并执行同一条语句 Run r=new Run(); Thread t1=new Thread(r,"t1"); Thread t2=new Thread(r,"t2"); t1.start(); t2.start(); } } class Run implements Runnable{ Timer t=new Timer(); //两个开始的线程调用同一个类中的方法 public void run(){ t.add(Thread.currentThread().getName()); } } class Timer{ int num=0; //计数 Thread t=new Thread(); public void add(String ThreadName){ //通过关键字synchronized,在执行方法的过程中锁定当前对象。 synchronized (this){ num++; try { t.sleep(1); } catch (InterruptedException e) { } System.out.println(ThreadName+"第"+num+"次执行"); } } }
使用对象互斥锁时可能出现死锁现象
死锁:线程A锁住了对象a,线程B锁住了对象b。
而线程A需要对象b才能继续执行,而线程B需要对象a才能继续执行
/* * 线程死锁例子 * */ public class Test { public static void main(String[] args) { //创建两个线程执行不同语句 Run r1=new Run(); Run r2=new Run(); r1.flag=1; r2.flag=0; Thread t1=new Thread(r1); Thread t2=new Thread(r2); t1.start(); t2.start(); } } class Run implements Runnable{ int flag=1; //通过flag的值区分两个不同线程执行的不同操作 static Object o1=new Object(),o2=new Object(); //flag==1的线程无法得到o2,flag==0的线程无法得到o1,进入死锁状态 public void run(){ System.out.println("flag="+flag); //flag==1的线程先锁住o1,在锁o2 if(flag==1){ synchronized(o1){ try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized(o2){ System.out.println("1"); } } } //flag==1的线程先锁住o2,在锁o1 if(flag==0){ synchronized(o2){ try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized(o1){ System.out.println("0"); } } } } }
尽量只锁定一个对象
一个线程锁定了一个对象A,另一个线程可以访问对象A对应类中未锁定对象的方法
public class Test { public static void main(String[] args) { //创建一个线程执行语句 Run r=new Run(); Thread t=new Thread(r); t.start(); //给线程锁定run()提供时间 try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } r.getb(); } } class Run implements Runnable{ int b=100; public void run(){ synchronized(this){ b=1000; try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("runner:b="+b); } } public void getb(){ System.out.println("m2:b="+b); } }
一个线程锁定了对象A,另一个线程不可以访问对象A对应类中另一个锁定对象的方法,只有当先执行的方法执行完后,另一个线程才可以访问另一个锁定对象的方法
public class Test { public static void main(String[] args) { Run r=new Run(); Thread t=new Thread(r); t.start(); try { Thread.sleep(8000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } r.m2(); System.out.println(r.b); } } class Run implements Runnable{ int b=100; public synchronized void m1(){ b=1000; try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void run(){ m1(); System.out.println("runner:b="+b); } public synchronized void m2(){ b=2000; System.out.println("m2:b="+b); } }
参考资料:尚学堂马士兵java视频教程