java 线程安全 synchronized同步块和同步方法的应用

package study_02;

public class unsafeThread{
	public static void main(String[] args) {
		Web12306 web12306 = new Web12306();
		new Thread(web12306,"线程A").start();
		new Thread(web12306,"线程B").start();
		new Thread(web12306,"线程C").start();
		
	}
}


class Web12306 implements Runnable{
	private int ticketNum = 10;
	private boolean flag = true;
	@Override
	public void run() {
		test();
	}
	public void  test() {
		while (flag) {
			if (ticketNum <= 0) {
				flag = false;
				break;
			}else {
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "----->"+ ticketNum--);
			}
		}
	}
}

运行后会发现

线程C----->9
线程A----->9
线程B----->10
线程A----->8
线程C----->8
线程B----->7
线程A----->6
线程B----->5
线程C----->6
线程A----->4
线程C----->3
线程B----->4
线程A----->2
线程C----->2
线程B----->2
线程C----->1
线程A----->-1
线程B----->0

出现两个9 还会出现-1这样的情况,这就是线程不安全

出现两个9是因为每个线程都有自己独立的工作空间,他们都和主存打交道,主存的ticketNum=10,每个线程把ticketNum=10拷贝到各自的工作空间里,当线程A获得ticketNum为10后拷贝到自己的工作空间里,然后进行IO操作,这是ticketNum还是为10.这时线程C被CPU调用,也获得tickNum为10拷贝到自己的空间,这时A重新被调用,然后修改tickNum数值,把ticketNUm减1改成9,线程C之后也被重新调用,把tickNum减1改成9.

出现-1是因为当还有一张票时,线程C被调用看到还有一张票,获得ticketNum= 1,然后进行10ms的IO操作,这时ticketNum还没有被修改还是为1,此时在线程B进行IO操作时,线程B也看到余票还有1,再次进入IO操作,同理线程C也是,当线程C重新被调用,对ticketNum减一,然后线程B被调用对ticketNum减一,同理线程A也是,最后显示线程C为1 线程B为0,线程A为-1.

加同步锁

package study_3;
/*
 * 同步方法 同步块
 * 
 * 
 * 
 */
public class synTest2{
	public static void main(String[] args) {
		synWeb12306 web12306 = new synWeb12306();
		new Thread(web12306,"线程A").start();
		new Thread(web12306,"线程B").start();
		new Thread(web12306,"线程C").start();
		
	}
}


class synWeb12306 implements Runnable{
	private int ticketNum = 10;
	private boolean flag = true;
	@Override
	public void run() {
		test();
	}
	public synchronized void test() {// 线程安全 同步方法 锁的是对象的资源
		while (flag) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			if (ticketNum <= 0) {
				flag = false;
				break;
			}else {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "------>" +ticketNum--);
			}
		}
	}
}
线程A------>10
线程A------>9
线程A------>8
线程A------>7
线程A------>6
线程A------>5
线程A------>4
线程A------>3
线程A------>2
线程A------>1

例子2

package study_02;

import java.util.ArrayList;
import java.util.List;

public class unsafeThread4 {
	public static void main(String[] args) throws InterruptedException {
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < 10000; i++) {
			new Thread(()->{
				list.add(Thread.currentThread().getName());
			}).start();
		}
		Thread.sleep(1000);//list里的元素数量
		System.out.println(list.size());
	}
}

结果为9998,按理来说应该为10000这是加同步锁,同步块

package study_02;

import java.util.ArrayList;
import java.util.List;

public class unsafeThread4 {
	public static void main(String[] args) throws InterruptedException {
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < 10000; i++) {
			new Thread(()->{
				synchronized (list) {//同步块
					list.add(Thread.currentThread().getName());
				}
			}).start();
		}
		Thread.sleep(1000);//list里的元素数量
		System.out.println(list.size());
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值