【JAVA高级】线程基础知识

7 篇文章 0 订阅

并发解决的问题

1.速度:避免了单线程阻塞  

2.完整的仿真涉及大量的任务,需要使用协作多线程

并发存在的问题

共享内存和I/O资源,编写多线程要协调多线程对资源的使用,以使得资源不会被多个任务同时使用。

线程驱动任务

线程可以驱动任务,所以需要一种描述任务的方式,这可以由runnable接口来提供。

  •    thread调用方式  new Thread(new Runnable())
  •    线程池调用方式:executorService .execute(Runnable runnable)

从任务中产生返回值

      如果你希望在任务完成时能够返回一个值,那需要使用callable而不是runnable,返回类型是callable的泛型参数类型。

  •    thread调用方式:new FutureTask<T>(new Callable())  new Thread(FutureTask futureTask);
  •    线程池调用的方式:executorService.submit(Callable callable)

thread.sleep方法和thread.yield()方法区别

Sleep方法,当前线程进入阻塞状态,但是不会释放锁。Yield方法,是进入到就绪状态,也不会释放锁,调用yield方法也只是建议相同优先级或更高的线程可以运行,因为调用yield方法的本线程处于就绪状态,低于本线程优先级的线程不会得到执行。

生产者消费者模式通用模板

* 1.锁{
 * 2.  while 条件不满足
 *         释放锁   ,  等待条件改变
 *     end while
 * 3.  生产或者消费
 * 4.  唤醒其他生产者或消费者线程
 * 5.  释放锁
 * }

线程的加入 Thread.join()方法

如某个线程执行了 t.join(),那么该线程会挂起,直到线程t执行结束才恢复。

此方法可以实现经典的3线程顺序输出问题。

对join方法的调用可以中断,做法是在调用线程上调用interrupt()方法。

线程池 Executor可以异常处理 UncaughtExceptionHandler

synchronized和reentrantLock的区别

区别点

syschronized

reentrantlock

锁的类型

非公平、可重入

可公平、可重入

锁的获取

获取不到一直等待

可以尝试获取

锁的释放

结束自动释放

必须在finally里面释放锁

锁的状态

无法判断

可判断

volatile的作用

保证了数据的可见性,每个线程都有自己的工作缓存,如果用volatile修饰,那么一旦数据发生改变,就会通知各个线程的工作缓存失效。

ThreadLocal使用

线程的本地存储,每一个线程都有一份变量的复制,也就避免了资源共享的问题,本质是空间换时间。代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ThreadLocalHolder {
	private static Logger LOGGER = LoggerFactory.getLogger(ThreadLocalHolder.class);
	private static ThreadLocal<Integer> data = new ThreadLocal<Integer>();

	public static void add() {

		if (data.get() == null) {
			data.set(0);
		} else {
			data.set(data.get() + 1);
		}
		LOGGER.info("Thread" + Thread.currentThread() + ":data=" + get());
	}

	public static Integer get() {
		return data.get();
	}

}
public class TaskRunnable implements Runnable {
	private int count = 0;

	public void run() {
		while (count < 10) {
			ThreadLocalHolder.add();
			count++;
		}
	}
    public static void main(String[] args) {
		ExecutorService executorService = Executors.newCachedThreadPool();
		executorService.execute(new TaskRunnable());
		executorService.execute(new TaskRunnable());
		executorService.shutdown();
	}

}

 执行的结果如下:

 INFO [pool-1-thread-1] - ThreadThread[pool-1-thread-1,5,main]:data=0
 INFO [pool-1-thread-1] - ThreadThread[pool-1-thread-1,5,main]:data=1
 INFO [pool-1-thread-2] - ThreadThread[pool-1-thread-2,5,main]:data=0
 INFO [pool-1-thread-1] - ThreadThread[pool-1-thread-1,5,main]:data=2
 INFO [pool-1-thread-2] - ThreadThread[pool-1-thread-2,5,main]:data=1
 INFO [pool-1-thread-2] - ThreadThread[pool-1-thread-2,5,main]:data=2

线程的状态

 

如何中断线程

        也许你想过使用标志位 iscanceled,通过控制这个字段,使得线程退出,但是线程退出还需要清理一些必要得资源,这就会引导你使用异常(这是滑向异常得不恰当用法,控制程序执行流程---出自《Thing in java》)

Thread.interrupt()提供了中断线程,这个方法将设置线程的中断状态,而Thread.interrupted()方法将中断状态复位。

Thread.interrupted()方法提供了离开run()方法而不抛出异常的第二种方法。

线程池中断线程的方法:Executor.shutdownNow(),那么它将发送一个interrupt()调用给它启动的每一个线程。那线程池如何中断某一个线程呢?可以通过Executor.submit()方法来启动线程,这将返回一个Future对象,调用Future.cancel()方法将中断单一线程。

可中断的操作:sleep()

不可中断的操作:synchronized锁(ReentrantLock支持中断)和I/O阻塞(nio类支持I/O中断)

线程之间的协作

任务协作的关键是握手,实现握手的基础特性是:互斥,在这种情况下,只有一个任务可以响应某个信号。Object.wait()和notify(),以及await()和signal()可以实现握手。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值