java 多线程 并发篇

1.什么是并发

与并发相近的一个概念是并行。
1.并行是在同一时间同时进行。
2.并发是在连续的间隔时间内连续发生。多线程在宏观上看起来是同一时间发生的,但实际上是在操作系统的调度下分配不同的时间片进行的。

所以java多线程在一般情况下运行顺序是并发且无法预测的。
例子

public class SynTest implements Callable<String>{
	static Integer i= new Integer(10);
	int index;
	static Object lock= new Object();
	public SynTest(int index) {
		// TODO Auto-generated constructor stub
		this.index = index;
		
	}
	@Override
	public String call() throws Exception {
		// TODO Auto-generated method stub
		System.out.println(index+","+i--);
		return null;
	}
}

这是一个实现callable接口的线程

public static void main(String[] args) {
	Set<SynTest> set = new HashSet<>();
	for(int i=0;i<10;i++) {
		set.add(new SynTest(i));
	}
	ExecutorService es=Executors.newFixedThreadPool(set.size());
	set.forEach((st)->{es.submit(st);});
	
}

运行结果如下
在这里插入图片描述
线程顺序是从0到9,共享变量每次都会减一,但是却出现了两个线程访问为10,且访问顺序是无序的(线程序号),所以多线程在运行时的调度是无序的,在访问同一个变量时就很容易出现线程不安全,出现“脏”数据的情况。

2. java线程使用synchronized 互斥

synchronized, wait, notify ,notifyAll是任何对象都具有的同步工具。
其中wait和notify,notifyAll是对象带有的默认方法。
synchronized是一个关键字。

wait() 等待,调用此方法后当前线程会进入waiting状态,等待唤醒。
notify()唤醒,此方法能够唤醒某个waiting的线程
notifyAll()唤醒,此方法能够唤醒所有正waiting的线程

wait和notify,notifyAll需要在synchronized块内才能正常工作。
他们之间协调工作必须是使用同一个对象,这个对象可以看做锁,wait锁住当前线程进入等待状态,notify唤醒被这个对象锁住的线程。

将上面的例子修改一下,加上synchronized同步块

public String call() throws Exception {
	// TODO Auto-generated method stub
	synchronized (lock) {
		System.out.println("第"+index+"个线程"+":"+i--);
	}
	return null;
}

synchronized{} 内的代码是同步代码,同一时间最多有且仅有一个线程执行这段代码,并且不会因线程调度被打断。
其中lock是锁(任意的一个对象),必须是所有线程共享的。

static Object lock= new Object();

在这里插入图片描述
可以看出加了synchronized同步后,线程的执行虽然还是无序但是已经没有脏数据了。

除了代码块
synchronized也可以加在普通方法和静态方法上面,只是此时的锁是无法指定的,普通方法上,锁是这个对象实例,静态方法则为这个类。
synchronized修饰普通方法,它锁定的是调用同个对象的这个方法的线程。
synchronized修饰静态方法,它锁定的是调用这个类的这个静态方法的线程。
也就是只要有一个线程访问这个(普通或静态)方法时,其他线程就无法访问从而被阻塞。

synchronized的显著作用就是实现多线程之间的互斥访问。

3.线程常用方法 yield(),join(),

Thread.yield(),静态方法,当前线程让出CPU资源,转为就绪态,重新进行竞争。(貌似不会释放对象锁,所以在synchronized中无效)

Thread.join(),普通方法,阻塞调用此方法的线程进入 TIMED_WAITING 状态,直到线程t完成,此线程再继续;(常用在阻塞主线程,等待线程执行完再执行主线程)。
源码中join方法是通过调用wait(0)来实现的,即主线程中调用线程t的join方法,join调用wait方法,前面说过调用任意一个对象的wait()都是使当前线程进入等待状态。(和FutureTask.get()获取结果有差不多的作用)
在这里插入图片描述

4.停止线程的方法 suspend(),stop(),interrupt()

stop()suspend() 方法不安全,无法保证线程操作的连续性,线程中可能进行到一半就被强行结束,造成“脏”数据,不建议使用。

中断在java中主要有3个方法,interrupt(),isInterrupted()和interrupted()。

  1. interrupt() 是普通方法,当线程调用这个方法后,线程的中断标志位就会改变。
  2. isInterrupted()是普通方法,用来判断线程的中断状态(true or false)。
  3. interrupted()有普通方法也有静态方法,恢复线程的中断标志

interrupt()不能中断在运行中的线程,它只能改变中断状态而已。
所以interrupt()配合isInterrupted()就能够起到安全停止线程的作用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值