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 = 5
b卖票:ticket = 5
b卖票:ticket = 4
a卖票:ticket = 4
b卖票:ticket = 3
a卖票:ticket = 3
b卖票:ticket = 2
a卖票:ticket = 2
a卖票:ticket = 1
b卖票:ticket = 1