java线程多线程
public class JavaStudy {
public static void main(String[] args) {
System.out.println("java线程学习");
//虚拟机线程管理的接口
ThreadMXBean threadMXBean =ManagementFactory.getThreadMXBean();
//取得线程管理信息
ThreadInfo[] threadInfo = threadMXBean.dumpAllThreads(false, false);
//Java天生多线程
for (ThreadInfo info : threadInfo) {
System.out.println("[" + info.getThreadId() + "]" + info.getThreadName());
}
System.out.println("");
System.out.println("beautiful line--------------" + Thread.currentThread());
System.out.println("");
UserThread userThread = new UserThread();
userThread.start();
//无返回值的任务
ImplRunnable implRunnable = new ImplRunnable();
new Thread(implRunnable).start();
//有返回值的任务
ImplCallable implCallable = new ImplCallable();
FutureTask<String> futureTask = new FutureTask<>(implCallable);
new Thread(futureTask).start();
try {
System.out.println("return==" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
1.png
如何新建线程
//How create Thread?
//extends Thread
public static class UserThread extends Thread {
@Override
public void run() {
super.run();
System.out.println(Thread.currentThread() + "I am extends Thread");
}
}
//implements Runnable interface
public static class ImplRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread() + "I am implements Runnable");
}
}
/*implements Callable ,allow return value**/
public static class ImplCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread() + "I am implements Callable");
return "I am ImplCallable return value";
}
}
总结:java天生是一个多线层的语言,新建线程有三中方式
1.new UserThread().start();
2.new Thread(new Runnable()).start();
3.new Thread(new FutureTask<>(new Callable())).start();
Runnable和Callable是对任务的抽象
对线程的抽象只有Thread
调用start()方法才是真的启动了一个线程
终止线程:
强制中断的后果:
协作式:
interrupted()叫停线程
isInterrupted()判断线程是否被叫停
Thread.isInterrupted() 调用之后又会把标志位改为false
UserThread.interrupted();
public static class UserThread extends Thread {
@Override
public void run() {
super.run();
System.out.println( "I am extends Thread"+isInterrupted());这会打印false
while (!isInterrupted()) {//被叫停就中断循环
System.out.println( "I am extends Thread is Running");
}
System.out.println( "I am extends Thread is Running" + isInterrupted());//这会打印true
}
}
join():哪个线程调用就哪个线程优先执行
yield():让出执行权,让出后系统可能又会选自己执行
start():线程准备好了,但是不一定马上执行,等系统调度
sleep():线程进入阻塞状态,sleep()时间到了或者interrupt()中断了就会进入就绪状态,属于线程的休眠,不会释放锁
wait():线程进入阻塞状态,notify()或者notifyAll()进入就绪状态,不满足执行条件,等通知,也可以设定一定时间后继续执行,阻塞其间释放锁
线程间的共享和协作:
synchronized 内置锁,同一时间只能有一个线程访问锁
用法 :
锁方法
public synchronized void countAdd() {//锁 this 就是当前对象
count++;
}
锁对象
private Object object = new Object();
public void countAdd() {this
synchronized (object) {//锁 自己new的对象, 也可这么写 synchronized (this)
count++;
}
}
这两种方法没太大区别都叫对象锁
提出疑问
假如当前对象有两个属性,其中一个加锁访问,另一个不加锁,起两个线程访问对应的两个属性,即线程1访问属性1,2访问2,访问加锁的属性的同时,不加锁的属性能被另一个线程访问么?
锁的是代码块,就是被synchronized包住的代码块或被synchronized修饰的方法
不被锁的其他代码块能被其他线程访问,不受影响
使用不同的对象锁不同的代码块,互不影响
使用相同的对象锁不同的代码块,哪个线程先得锁哪个线程先得访问
类锁
静态方法 static 后面加synchronized 锁.class对象,其实就是对象锁
总结:看似锁对象其实是作用在代码块,对象就像是一把锁的唯一标识
什么是线程间的协作?
条件不符时阻塞等待唤醒,修改条件唤醒阻塞线程,
wait() notify() notifyAll() 如何理解和使用?
等待通知的标准范式
等待方:
1.获取对象的锁
2.检查条件,条件不满足时 wait()
3.条件满足时,执行业务代码
syn(对象){
whilw(条件不满足){
对象.wait()//调通wait()锁就会被释放
}
//执行业务代码
}
通知方:
1.获取对象的锁
2.修改条件
3.通知等待方
syn(对象){
//执行业务代码,修改条件
对象.notifyAll()//并不会释放
}//代码块执行完之后才会释放
public class CountBean {
public static final int MaxCount = 5;
private int i = 0;
public synchronized void Iadd() {//线程1调用这
i++;
System.out.println(Thread.currentThread().getName() + " i=" + i);
notifyAll();
}
public synchronized int getI() throws InterruptedException {//线程2调用这
while (i < MaxCount) {
wait();//阻塞 等其他线程占有时调用notify或notifyAll方法,并再次获得锁后,条件一直符合,就一直循环阻塞
}
return i;
}
}
ThreadLocal:线程隔离
static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {//静态修饰保证全虚拟机只有一份
@Override
protected Integer initialValue() {//初始化值
return 0;
}
};
private Runnable runnable = new Runnable() {//假如三个线程都跑这个任务
@Override
public void run() {
for (int k = 0; k <3 ; k++) {//看起来是使用了一个threadLocal对象,但是每个线程之间没有影响
int i = threadLocal.get();
i++;
threadLocal.set(i);
System.out.println(Thread.currentThread().getName() + " i=" + threadLocal.get());//正常的打印出三个线程的累加
}
}
};
2.png
显示锁:Lock
synchronized 获取锁没有中断,就是没拿到锁我就等着,没有尝试获取锁
Lock是个接口,jdk有几个实现类:
使用范式
private Lock lock = new ReentrantLock();
public void main() {
lock.lock();
try {
//业务代码,有可能发生异常
} finally {//不管业务代码怎么样,一定能释放锁
lock.unlock();
}
}
ReentrantLock 可重入锁
什么是可重入锁:线程拿到锁,没释放锁,再次访问同一个锁,还能拿到这个锁,拿多少次就累加记录,这就是可重入锁,synchronized也是可重入锁,在递归调用有锁的方法时防止自己锁死自己。
锁的公平非公平:
公平:先取锁的线程一定先拿到锁
非公平:先取锁的线程不一定先拿到(性能更好 synchronized是非公平,ReentrantLock 默认非公平 构造传true就是公平锁)
为什么非公平更好?
线程挂起唤醒,上下文切换大约需要20000个时间周期,挂起一次20000,唤醒一次20000,
如果是公平锁就得等前面先挂起的线程先拿锁执行,如果刚好可以拿锁不用挂起再唤醒就可以省去40000个时间周期,整体来说非公平锁性能优于公平锁,大概的说。
排他锁:有且只有一个线程能拿到的锁(synchronized)
ReentrantReadWriteLock 读写锁
读:允许有多个线程拿锁读取文件数据,排斥写线程,防止数据不一致
写:只允许一个线程写数据,排斥其他线程,防止数据不一致
为什么会有读写锁?
在生活中读比写的比例大约在10:1左右,读写分离,资源分配合理
public class Merchandise {
private final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
private final Lock getLock = reentrantReadWriteLock.readLock();//读锁 10个线程访问
private final Lock setLock = reentrantReadWriteLock.writeLock();//写锁 1个线程访问
public void setPrice() throws InterruptedException {
setLock.lock();
try {
Thread.sleep(5);//模拟写花的时间
} finally {
setLock.unlock();
}
}
public void getPrice() throws InterruptedException {
getLock.lock();
try {
Thread.sleep(5);//模拟读花的时间
} finally {
getLock.unlock();
}
}
}
Condition:
public class Express {
public static final String ST_shanghai = "shanghai";
public static final String ST_beijing = "beijing";
private String currentStation = ST_shanghai;
private int distance = 0;
private Lock lock = new ReentrantLock();//一把锁多个开关
private Condition stationCondition = lock.newCondition();//开关1
private Condition distanceCondition = lock.newCondition();//开关2
public void changeStation(String station) {
lock.lock();
try {
currentStation = station;//条件改变
stationCondition.signal();//开关1发出一个通知
} finally {
lock.unlock();
}
}
public void changeDistance(int distance) {
lock.lock();
try {
this.distance = distance;//条件改变
distanceCondition.signalAll();//开关2发出一个通知
// distanceCondition.signal();//开关2发出一个通知
} finally {
lock.unlock();
}
}
public void waitStation() {
lock.lock();
try {
while (currentStation.equals(ST_shanghai)) {
try {
System.out.println(Thread.currentThread().getName() + " waitStation");
stationCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " Station is Change");
} finally {
lock.unlock();
}
}
public void waitDistance() {
lock.lock();
try {
while (distance < 100) {
try {
System.out.println(Thread.currentThread().getName() + " waitDistance");
distanceCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " Distance is Change");
} finally {
lock.unlock();
}
}
}
线程池的优点 :
1.复用,节约资源 2.响应速度块(省掉创建的时间)3.提高线程的可管理
简单的线程池:
public class ThreadPool {
private int coreThreadCount = 5;
private int defaultTaskCount = 100;
private WorkThread[] workThreads;
private final BlockingQueue<Runnable> taskQueue;
public ThreadPool() {
taskQueue = new ArrayBlockingQueue<>(defaultTaskCount);
workThreads = new WorkThread[coreThreadCount];
for (int i = 0; i < coreThreadCount; i++) {
workThreads[i] = new WorkThread();
workThreads[i].start();
}
System.out.println("cpuCoreCount=" + Runtime.getRuntime().availableProcessors());
}
public void execute(Runnable task) {
try {
taskQueue.put(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void destroy() {
for (int i = 0; i < coreThreadCount; i++) {
workThreads[i].interrupt();
workThreads[i] = null;
}
taskQueue.clear();
}
public class WorkThread extends Thread {
@Override
public void run() {
super.run();
Runnable runnable = null;
try {
while (!isInterrupted()) {
runnable = taskQueue.take();
if (runnable != null) {
runnable.run();
}
runnable = null;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
ThreadPool threadPool = new ThreadPool();
for (int i = 0; i < 10; i++) {
threadPool.execute(new ImplRunnable("Task" + i));
}
}
public static class ImplRunnable implements Runnable {
private String taskName;
public ImplRunnable(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("complete:" + taskName);
}
}
jdk线程池:
corePoolSize: 核心线程数,线程池保留的最小线程数
maximumPoolSize: 最大线程数,当任务队列装不下之后就开始创建新的线程
keepAliveTime: 空闲线程存活时间,保留的线程数等于核心线程数
unit: 时间单位,对应keepAliveTime
workQueue: 任务缓冲阻塞队列,核心线程都在工作时候添加到队列
threadFactory: 搞线程名的
handler: 溢出策略(饱和策略,拒绝策略),当最大线程数也满了之后开始响应策略
jdk提供的几种策略:
AbortPolicy:直接抛出异常(jdk默认)
CallerRunsPolicy:哪个线程提交的任务它自己执行
DiscardPolicy:直接丢到要放进来的任务
DiscardOldestPolicy:丢弃阻塞队列最先进去的任务
自定义策略:自己实现RejectedExecutionHandler
BlockingQueue:
add remove
offer poll
put take 阻塞
常用的BlockingQueue:
ArrayBlockingQueue:
LinkedBlockingQueue:
合理使用分配线程:
Cpu密集型:不要超过Cpu同时运行的线程数 Runtime.getRuntime().availableProcessors()取得线程数
IO密集型 :2*Cpu同时运行的线程数
混合型:拆分成以上两个
AsyncTask:
volatile 保证可见性 不保证原子性
网友评论