线程不安全的原因
?
package ThreadTest;public class ThreadTest {public static void main(String args[]){ MyThread mt = new MyThread() ; // 定义线程对象 Thread t1 = new Thread(mt) ; // 定义Thread对象 Thread t2 = new Thread(mt) ; // 定义Thread对象 Thread t3 = new Thread(mt) ; // 定义Thread对象 t1.start() ; t2.start() ; t3.start() ; }}class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 public void run(){// synchronized (this){ while(ticket>0){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("卖票:ticket = " + ticket-- ); }// } }}?
?
?
线程不安全条件
?
1 mt为一个对象实例
2 存在多个线程同时修改一个对象实例的属性,每个线程都有自己的临时空间用来保存对象实例的值,所以该值在被修改后不会马上同步到对象中,造成别的线程读到的不是对象实例最新的值,从而导致数据脏读,再造成脏写
?
运行结果如下
?
?
卖票:ticket = 5
卖票:ticket = 5
卖票:ticket = 4
卖票:ticket = 3
卖票:ticket = 2
卖票:ticket = 3
卖票:ticket = 1
卖票:ticket = 0
卖票:ticket = -1
?
?
?
修改: ?同步代码块,使一个时间里,只有一个线程可以访问该代码。从而保证数据的修改是单线程同步的
?
?
class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 public void run(){ synchronized (this){ while(ticket>0){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("卖票:ticket = " + ticket-- ); } } }}卖票:ticket = 5卖票:ticket = 4卖票:ticket = 3卖票:ticket = 2卖票:ticket = 1??? ? ? ?synchronized (this){
}
同步的是一个属性,而不是代码段(而this 代表了本类,即此时本类中的别的方法也被同步?)
?
?
改进 ?用byte[] lock = {0}; 代替this. 比较省内存
?
class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 private byte[] lock = {0}; public void run(){ synchronized (lock){ while(ticket>0){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("卖票:ticket = " + ticket-- ); } } }}?
或者直接synchronized ?多线程访问修改的属性 ?synchronized的是数组
?
class MyThread implements Runnable{ private int[] ticket = {5} ; // 假设一共有5张票 public void run(){ synchronized(ticket){ sale(); } } private void sale(){ while(ticket[0]>0){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("卖票:ticket = " + ticket[0]-- ); } }}??
2 同步方法
?
?
?
class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 public void run(){ sale(); } private synchronized void sale(){ while(ticket>0){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("卖票:ticket = " + ticket-- ); } }}??
?
?
?
?
?
?
以下为线程安全的,但是继承Thread类后,资源(ticket )没有共享,各自卖各自的票。而实现runnable接口是可以资源共享的
?
package ThreadTest;public class ThreadTestFirst {public static void main(String args[]){MyThreadF a = new MyThreadF("a");MyThreadF b = new MyThreadF("b");a.start();b.start(); }}class MyThreadF extends Thread{ private int ticket = 5 ; // 假设一共有5张票 private String name; public MyThreadF(String name) {this.name = name;} public void run(){ while(ticket>0){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.name + "卖票:ticket = " + ticket-- ); } }}?
?
a卖票:ticket = 5b卖票:ticket = 5b卖票:ticket = 4a卖票:ticket = 4b卖票:ticket = 3a卖票:ticket = 3b卖票:ticket = 2a卖票:ticket = 2a卖票:ticket = 1b卖票:ticket = 1?
?