本章主要是介绍线程的创建与使用,以及一些常用的方法介绍与代码示例,有助于理解。这里主要针对一些常用方法的介绍。
一、等待线程执行终止的 Join方法
public class JoinDemo {
public static void main(String[] args) throws InterruptedException{
Thread thread0 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread-1 over");
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread-2 over");
}
});
thread0.start();
thread1.start();
System.out.println("all child thread over");
thread0.join();
thread1.join();
}
}
二、让线程睡眠的sleep方法
public class SleepDemo {
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException{
// 验证 调用sleep方法 执行时睡眠线程不会释放持有的锁,直到睡眠结束执行完毕
Thread thread0 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("thread-1 is in sleep");
Thread.sleep(10000);
System.out.println("thread-1 is awaked");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("thread-2 is in sleep");
Thread.sleep(10000);
System.out.println("thread-2 is awaked");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
thread0.start();
thread1.start();
}
static class innerOne{
// 验证 子线程执行sleep方法 在睡眠期间,主线程中断了它,子线程抛出InterruptedException,
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("thread 子线程 睡了");
Thread.sleep(10000);
System.out.println("thread 子线程 醒了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
Thread.sleep(2000);
thread.interrupt();
}
}
}
三、让出CPU执行权的 yield方法
/**
* yield 让出cpu使用权,线程调度器可以理会也可以忽略
* 当调度器接收让出权后,时间片轮转到下一个,下一个线程可能是 非让出使用权的线程,也可以是让出使用权的线程
*/
public class YieldDemo implements Runnable{
public YieldDemo() {
Thread t = new Thread(this::run);
t.start();
}
@Override
public void run() {
for (int i=0; i<5; i++){
if (i%5 == 0){
System.out.println(Thread.currentThread() + "yield cpu...");
Thread.yield();
}
}
System.out.println(Thread.currentThread() + "is over");
}
public static void main(String[] args) {
new YieldDemo();
new YieldDemo();
new YieldDemo();
}
}
四、线程中断
通过设置线程的中断标志 并不能直接终止该线程的执行,而是被中断的线程根据中断状态自行处理
例如 有线程A、线程B 两个线程,当线程A运行时,线程B 可以调用线程A 的Interrupt方法来设置线程A 的中断标志,这里仅仅是设置标志,线程A 并没有被中断,还会继续执行如果线程A 因为调用了 wait函数、join方法或sleep方法而被阻塞挂起,这时调用线程A 的interrupt方法 线程A 会在调用这些方法的地方抛出InterruptedException异常而返回。
public class InterruptDemo {
/**
* 线程使用Interrupted优雅退出的例子
*
* public void run(){
* try{
* //to do something...
* //线程退出条件
* while(!Thread.currentThread().isInterrupted() && more work to do){
* // do something
* }
* }catch(InterruptedException e){
* // 线程在 sleep 或者 wait 时被中断
* }finally{
* // 如果需要 cleanup
* }
* }
*/
public static void main(String[] args) throws InterruptedException {
// 根据中断标志判断线程是否终止
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 如果当前线程中断则退出循环
while (!Thread.currentThread().isInterrupted()){
System.out.println(Thread.currentThread() + "hello!");
}
}
});
// 启动子线程
thread.start();
// 让主线程睡眠1S ,以便中断前让子线程输出
Thread.sleep(1000);
// 中断子线程
System.out.println("子线程 中断---");
thread.interrupt();
//等待子线程输出
thread.join();
System.out.println("main thread is over---");
}
static class innerOne{
// 当线程调用sleep wait join等阻塞挂起时调用 interrupt方法
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(20000000);
System.out.println("thread is awaked");
} catch (InterruptedException e) {
System.out.println("thread is interrupted while sleeping");
return;
}
System.out.println("thread-leaving normally");
}
});
thread.start();
Thread.sleep(1000);
thread.interrupt();
thread.join();
System.out.println("main thread is over");
}
}
static class innorTwo{
// 通过例子了解 interrupted() 和 isInterrupted() 方法区别
/**
* 在interrupted()方法内部是获取当前线程的中断状态,
* 这里虽然调用了thread的interrupted()方法,但是获取的是主线程的中断标志,因为主线程是当前线程
*/
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (;;){
}
}
});
// 启动线程
thread.start();
// 设置中断标志
thread.interrupt();
// 获取中断标志
System.out.println("isInterrupted:" + thread.isInterrupted());
// 获取中断标志并重置
System.out.println("interrupted:" + thread.interrupted());
// 获取中断标志并重置
System.out.println("interrupted:" + Thread.interrupted());
// 获取中断标志
System.out.println("isInterrupted:" + thread.isInterrupted());
thread.join();
System.out.println("main thread is over");
}
}
}
五、线程死锁
public class DeadLockDemo {
// 死锁 样例
private static Object resourceA = new Object();
private static Object resourceB = new Object();
public static void main(String[] args) {
Thread thread0 = new Thread(new Runnable() {
@Override
public void run() {
synchronized(resourceA){
System.out.println(Thread.currentThread() + "get resourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting resourceB");
synchronized (resourceB){
System.out.println(Thread.currentThread() + "get resourceB");
}
}
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceB){
System.out.println(Thread.currentThread() + "get resourceB");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting resourceA");
synchronized (resourceA){
System.out.println(Thread.currentThread() + "get resourceA");
}
}
}
});
thread0.start();
thread1.start();
}
static class innorOne{
// 修改申请资源的有序性,避免死锁发生
public static void main(String[] args) {
Thread thread0 = new Thread(new Runnable() {
@Override
public void run() {
synchronized(resourceA){
System.out.println(Thread.currentThread() + "get resourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting resourceB");
synchronized (resourceB){
System.out.println(Thread.currentThread() + "get resourceB");
}
}
}
});
Thread thread1 = new Thread(new Runnable() {
// 修改 该线程的申请资源顺序
@Override
public void run() {
synchronized (resourceA){
System.out.println(Thread.currentThread() + "get resourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting resourceB");
synchronized (resourceB){
System.out.println(Thread.currentThread() + "get resourceB");
}
}
}
});
thread0.start();
thread1.start();
}
}
}
六、ThreadLocal
/**
* 同步的方式:加锁、ThreadLocal
* ThreadLocal 由JDK包提供
*/
public class ThreadLocalDemo {
// 使用示例
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void print(String str){
// 打印 当前线程的本地内存中 threadLocal变量的值
System.out.println(str + ":" + threadLocal.get());
// 移除 当前线程本地内存中 threadLocal变量的值
threadLocal.remove();
}
public static void main(String[] args) {
Thread thread0 = new Thread(new Runnable() {
@Override
public void run() {
threadLocal.set("thread-1 local variable");
print("thread-1");
System.out.println("线程一 移除后:" + threadLocal.get());
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
threadLocal.set("thread-2 local variable");
print("thread-2");
System.out.println("线程二 移除后:" + threadLocal.get());
}
});
thread0.start();
thread1.start();
}
static class innorOne{
/**
* ThreadLocal 不支持继承
* 同一个ThreadLocal变量在主线程设置后,在子线程中获取不到
*/
public static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("hello world");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("threadLocal:" + threadLocal.get());
}
});
thread.start();
System.out.println("main:" + threadLocal.get());
}
}
static class innorTwo{
/**
* InheritableThreadLocal 继承自ThreadLocal
* 提供一个特性,让子线程可以访问父线程中设置的本地变量
*/
public static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("hello world");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("threadLocal:" + threadLocal.get());
}
});
thread.start();
System.out.println("main:" + threadLocal.get());
}
}
}