尚未启动的线程处于此状态
在Java虚拟机中执行的线程处于此状态
被阻塞等待监视器锁定的线程处于此状态
正在等待另一个线程执行特定动作的线程处于此状态
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
已退出的线程处于此状态
一个线程可以在给定时间点,处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态。
package cn.lacknb.test.callable;
import java.util.concurrent.TimeUnit;
/**
* @author gitsilence
* @version 1.0
* @date 2020/9/17 0017 下午 16:54
* @mail gitsilence@lacknb.cn
*/
public class ThreadState implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("running -- > " + i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new ThreadState());
Thread.State state = t.getState();
System.out.println("启动前的状态 ---> " + state);
t.start();
state = t.getState();
System.out.println("启动后的状态 ---> " + state);
while (state != Thread.State.TERMINATED ) {
TimeUnit.NANOSECONDS.sleep(800);
state = t.getState();
System.out.println("当前的状态 ---> " + state);
}
state = t.getState();
System.out.println("最终的状态 ---> " + state);
}
}
重新竞争cpu -- 礼让
package cn.lacknb.test.callable;
/**
* @author gitsilence
* @version 1.0
* @date 2020/9/17 0017 下午 16:06
* @mail gitsilence@lacknb.cn
*/
public class TestYield implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " ---> 开始执行");
// 礼让
Thread.yield();
System.out.println(Thread.currentThread().getName() + " ---> 结束执行");
}
public static void main(String[] args) {
Thread t = new Thread(new TestYield(), "子线程A ---> ");
t.start();
Thread t2 = new Thread(new TestYield(), "子线程B ---> ");
t2.start();
}
}
合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞。
package cn.lacknb.test.callable;
/**
* @author gitsilence
* @version 1.0
* @date 2020/9/17 0017 下午 16:28
* @mail gitsilence@lacknb.cn
*/
public class TestJoin implements Runnable {
@Override
public void run() {
for (int i = 0; i < 300; i++) {
System.out.println("join ---> " + i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new TestJoin());
t.start();
Thread.sleep(1);
for (int i = 0; i < 300; i++) {
if (i == 50) {
t.join();
}
System.out.println("main ----> " + i);
}
}
}
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度按照优先级决定应该调哪个线程来执行。
线程的优先级用数字表示,范围从 1 ~ 10
使用以下方式改变或获取优先级
getPriority()
setPriority(int xxx)
优先级不能真正决定 高的先执行,决定权还是在cpu。
package cn.lacknb.test.callable;
/**
* @author gitsilence
* @version 1.0
* @date 2020/9/17 0017 下午 17:18
* @mail gitsilence@lacknb.cn
*/
public class TestPriority implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " ---> " + Thread.currentThread().getPriority());
}
public static void main(String[] args) {
// 默认 优先级 是 5
System.out.println("main ---> " + Thread.currentThread().getPriority());
Thread t1 = new Thread(new TestPriority(), "线程1");
t1.setPriority(4);
Thread t2 = new Thread(new TestPriority(), "线程2");
Thread t3 = new Thread(new TestPriority(), "线程3");
Thread t4 = new Thread(new TestPriority(), "线程4");
t4.setPriority(10);
Thread t5 = new Thread(new TestPriority(), "线程5");
t5.setPriority(2);
Thread t6 = new Thread(new TestPriority(), "线程6");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如,后台记录操作日志,监控内存,垃圾回收等待...
setDaemon(Boolean flag) 默认为false
同步方法
public synchronized void add () {
}
同步代码块
synchronized (对象或者是class) {
}
synchronized默认锁的是this,当前对象。
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了当问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制 synchronized,当一个线程获得对象的排他锁,独占资源,其他线程必须等待,使用后释放锁即可
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
加上 synchronized,效率明显变低,但是安全。下面例子真实反映出问题。
package cn.lacknb.test.lock;
/**
* @author gitsilence
* @version 1.0
* @date 2020/9/17 0017 下午 19:26
* @mail gitsilence@lacknb.cn
*/
public class SynchronizedTest implements Runnable {
private int count = 1000;
@Override
public void run() {
// 加上同步代码块
synchronized (this) {
for (int i = 0; i < 500; i++) {
if (count > 0) {
count--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
System.out.println(Thread.currentThread().getName() + " ------> " + count);
}
}
// 不加 同步代码块
// for (int i = 0; i < 500; i++) {
// if (count > 0) {
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// count--;
// } else {
// break;
// }
// System.out.println(Thread.currentThread().getName() + " ------> " + count);
// }
}
public static void main(String[] args) {
SynchronizedTest synchronizedTest = new SynchronizedTest();
new Thread(synchronizedTest, "线程A").start();
new Thread(synchronizedTest, "线程B").start();
}
}
访问同一个对象的 同步代码块 和 非同步代码块
package cn.lacknb.test.lock;
/**
* @author gitsilence
* @version 1.0 访问 非 同步代码块 不受影响
* @date 2020/9/17 0017 下午 19:55
* @mail gitsilence@lacknb.cn
*/
public class SynchronizedTest02 {
public void hi () throws InterruptedException {
synchronized (this) {
for (int i = 0; i < 100; i++) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " ----> hi ---> " + i);
}
}
}
public void hello () throws InterruptedException {
for (int i = 0; i < 100; i++) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " ----> hello ---> " + i);
}
}
public static void main(String[] args) {
final SynchronizedTest02 synchronizedTest02 = new SynchronizedTest02();
new Thread(() -> {
try {
synchronizedTest02.hi();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
synchronizedTest02.hello();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
对于以上规则对象锁同样适用。
package cn.lacknb.test.lock;
/**
* @author gitsilence
* @version 1.0 同一个对象锁,获得对象锁的才能运行。
* @date 2020/9/17 0017 下午 20:03
* @mail gitsilence@lacknb.cn
*/
public class SynchronizedTest03 {
static class TotalCount {
private int count = 100;
public void decrease1 () {
for (int i = 0; i < 50; i++) {
count--;
System.out.println(Thread.currentThread().getName() + " ----> " + count);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void decrease2 () {
for (int i = 0; i < 50; i++) {
count--;
System.out.println(Thread.currentThread().getName() + " ----> " + count);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void execute (TotalCount totalCount) {
synchronized (totalCount) {
totalCount.decrease1();
}
}
public void execute2 (TotalCount totalCount) {
synchronized (totalCount) {
totalCount.decrease2();
}
}
public static void main(String[] args) {
final TotalCount totalCount = new TotalCount();
final SynchronizedTest03 synchronizedTest03 = new SynchronizedTest03();
new Thread(() -> synchronizedTest03.execute2(totalCount)).start();
new Thread(() -> synchronizedTest03.execute(totalCount)).start();
}
}
https://blog.csdn.net/qq_38737992/article/details/89607758
synchronized: 是自动获取锁和释放锁
Lock: 是手动获取锁和释放锁、可中断的获取锁、超时获取锁。
Lock锁,可以得到和 synchronized一样的效果,即实现原子性、有序性和可见性。
相较于synchronized,Lock锁可手动获取锁和释放锁、可中断的获取锁、超时获取锁。
Lock 是一个接口,两个直接实现类:ReentrantLock(可重入锁), ReentrantReadWriteLock(读写锁)。
lock只有代码块锁,synchronized有代码锁和方法锁
使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
优先使用的顺序:
Lock > 同步代码块(已经进入了方法体,分配了相应资源)> 同步方法(在方法体外)
这是一个线程同步的问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件。
wait 表示线程一直等待,直到其他线程通知,与sleep不同,wait会释放锁。
wait(int timeout) 指定等待的毫秒数
notify() 唤醒一个处于等待状态的线程
notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程优先调度。
均是object类的方法, 都只能在同步方法或者同步代码块中使用,否则会抛出异常IllegalMonitorStateException
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
package cn.lacknb.test.proconsumer;
/**
* @author gitsilence
* @version 1.0 利用缓冲区解决: 管程法
* @date 2020/9/19 0019 上午 10:19
* @mail gitsilence@lacknb.cn
*/
public class ProviderConsumer {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Provider(synContainer).start();
new Consumer(synContainer).start();
}
}
/**
* 生产者
*/
class Provider extends Thread {
SynContainer synContainer;
public Provider (SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println("生产了 第" + i + "只鸡");
synContainer.push(new Chicken(i));
}
}
}
/**
* 消费者
*/
class Consumer extends Thread {
SynContainer synContainer;
public Consumer (SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了 第" + synContainer.pop().id + "只鸡");
}
}
}
/**
* 产品
*/
class Chicken {
int id;
public Chicken(int id) {
this.id = id;
}
}
/**
* 缓冲区
*/
class SynContainer {
// 容器大小
Chicken[] chickens = new Chicken[10];
// 容器计数器
int count = 0;
// 生产者放入产品
public synchronized void push (Chicken chicken) {
// 如果容器满了,就需要等待消费者 消费
if (count == chickens.length - 1) {
// 通知消费者消费
try {
// 生产者等待
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果没有满,我们就需要丢入产品
chickens[count] = chicken;
count++;
// 通知消费者 消费了
this.notifyAll();
}
// 消费者 消费产品
public synchronized Chicken pop () {
// 判断能否消费
if (count == 0) {
// 等待生产者生产,消费者等待。
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果可以消费
count--;
Chicken chicken = chickens[count];
// 吃完了,通知生产者生产
this.notifyAll();
return chicken;
}
}
取一个标志位 flag
package cn.lacknb.test.proconsumer;
/**
* @author gitsilence
* @version 1.0
* @date 2020/9/19 0019 上午 11:08
* @mail gitsilence@lacknb.cn
*/
public class ProviderConsumer02 {
public static void main(String[] args) {
Tv tv = new Tv();
new Player(tv).start();
new Watcher(tv).start();
}
}
// 生产者 -> 演员
class Player extends Thread {
Tv tv;
public Player (Tv tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
this.tv.play(" 快乐大本营 ");
} else {
this.tv.play( " 变形记 ");
}
}
}
}
// 消费者 -> 观众
class Watcher extends Thread {
Tv tv;
public Watcher (Tv tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
this.tv.watch();
}
}
}
// 产品 -> 节目
class Tv {
// 演员表演 观众等待 T
// 观众观看,演员等待 F
String voice; // 表演的节目
boolean flag = true; // 为true,说明当前没节目,需要进行表演
// 表演
public synchronized void play (String voice) {
if (!flag) {
// 有节目,观众正在观看,等待观众观看完毕
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了: " + voice);
this.flag = !this.flag;
this.voice = voice;
// 表演之后,通知观众可以看了。
this.notifyAll();
}
// 观看
public synchronized void watch () {
if (flag) {
// 说明 没节目,需要等待 演员 表演完节目
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 有节目了之后,观众可以观看了
System.out.println("观看了 " + voice + " 节目");
this.flag = !this.flag;
// 节目看完了,需要通知演员继续表演节目了
this.notifyAll();
}
}
经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路:可以提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:
ExecutorService : 真正的线程池接口。常见子类ThreadPoolExecutor
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池。
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors返回的线程池对象的弊端如下:
1)FixedThreadPool和SingleThreadPool:
允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
2)CachedThreadPool:
允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。Positive example 1:
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());Positive example 2:
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown
//Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdownPositive example 3:
property
refproperty
ref
property
ref
">
<property name=
<property name=