目录

多线程编程核心技术整理

前言

2016年5月12日东哥在微信读书APP上送给我一本书《JAVA多线程编程核心技术》,作者高洪岩。在接下来的7天内读完了,感觉这本书写的挺好,作者基本把所有的知识点都结合代码例子来讲解,容易被程序员接受。其实在读的过程当中,就想着要把这本书的知识点做个整理,用于备忘也用于更好的掌握多线程。可能在我尝试整理知识点的时候,某些我觉得比较不常用的,我会比较简单的整理。

多线程基础

进程和多线程的概念及线程的优点

比如WINDOWS任务管理器里,看到的QQ.EXE,就是一个进程

比如QQ中的视频,发送文件,发送文字图片等,都是独立在运作的“线程”

多线程或者说多任务操作系统,可以最大限度地利用CPU的空闲时间在不同的任务之间不停的切换,由于切换的速度非常快,使使用者感觉多个任务是在同时进行的。当然后来也出现多个CPU,或者一个CPU多核就是为了加快机器运算。

使用多线程

打印主线程的名字

Test.java
package com.gxx.threads.study.test1;
 
/**
 * 测试类-打印主线程的名字
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		/**
		 * 打印main方法当前线程名字
		 * 输出:main
		 */
		System.out.println(Thread.currentThread().getName());
	}
}

输出

main

两种实现线程类的方法

MyThread1.java
package com.gxx.threads.study.test2;
 
/**
 * 继承Thread实现线程类
 * @author Gxx
 */
public class MyThread1 extends Thread {
	/**
	 * 覆盖Thread中的run方法
	 */
	@Override
	public void run() {
		System.out.println("MyThread1.run()");
	}
}
MyThread2.java
package com.gxx.threads.study.test2;
 
/**
 * 实现Runnable实现线程类
 * @author Gxx
 */
public class MyThread2 implements Runnable {
	/**
	 * 实现Runnable中的run方法
	 */
	@Override
	public void run() {
		System.out.println("MyThread2.run()");
	}
}

本质上并没有什么区别,但是由于JAVA只支持单继承,如果继承了Thread就不能继承其它的父类了,所以绝大多数情况下是由于这个,而Thread类其实也实现了Runnable接口。

测试start()、run()和多次start()

start()通过“线程规划器”此线程已经准备就绪,等待调用run(),CPU在不确定的时间调用run()

直接执行run,就不是“线程规划器”来调度了,而是执行run()的当前线程直接调用方法,如果是main()中调用,则当前线程就是main

多次start()会抛出异常java.lang.IllegalThreadStateException,报线程状态异常

MyThread.java
package com.gxx.threads.study.test3;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 构造方法
	 */
	public MyThread(){
		System.out.println("线程[" + Thread.currentThread().getName() + "]执行构造方法");
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("线程[" + Thread.currentThread().getName() + "]执行run");
	}
}
Test.java
package com.gxx.threads.study.test3;
 
/**
 * 测试类-测试start和run和多次start
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		MyThread thread = new MyThread();
		thread.setName("线程A");//设置线程名字
		thread.run();
		thread.start();
		thread.start();
	}
}

输出

线程[main]执行构造方法
线程[main]执行run
线程[线程A]执行run
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Thread.java:705)
	at com.gxx.threads.study.test3.Test.main(Test.java:17)

不共享变量,线程安全

MyThread.java
package com.gxx.threads.study.test4;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 计数
	 */
	int count = 10;
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("线程[" + Thread.currentThread().getName() + "]执行count=" + (count--));
	}
}
TestSafe.java
package com.gxx.threads.study.test4;
 
/**
 * 测试类-不共享变量,线程安全
 * @author Gxx
 */
public class TestSafe {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		MyThread thead1 = new MyThread();
		MyThread thead2 = new MyThread();
		MyThread thead3 = new MyThread();
		MyThread thead4 = new MyThread();
		MyThread thead5 = new MyThread();
		MyThread thead6 = new MyThread();
		MyThread thead7 = new MyThread();
		MyThread thead8 = new MyThread();
		MyThread thead9 = new MyThread();
		MyThread thead10 = new MyThread();
		thead1.start();
		thead2.start();
		thead3.start();
		thead4.start();
		thead5.start();
		thead6.start();
		thead7.start();
		thead8.start();
		thead9.start();
		thead10.start();
	}
}

输出

线程[Thread-0]执行count=10
线程[Thread-2]执行count=10
线程[Thread-1]执行count=10
线程[Thread-3]执行count=10
线程[Thread-4]执行count=10
线程[Thread-5]执行count=10
线程[Thread-6]执行count=10
线程[Thread-7]执行count=10
线程[Thread-8]执行count=10
线程[Thread-9]执行count=10

共享变量,线程不安全

TestNotSafe.java
package com.gxx.threads.study.test4;
 
/**
 * 测试类-共享变量,线程不安全
 * @author Gxx
 */
public class TestNotSafe {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		MyThread thread = new MyThread();
		Thread thead1 = new Thread(thread);
		Thread thead2 = new Thread(thread);
		Thread thead3 = new Thread(thread);
		Thread thead4 = new Thread(thread);
		Thread thead5 = new Thread(thread);
		Thread thead6 = new Thread(thread);
		Thread thead7 = new Thread(thread);
		Thread thead8 = new Thread(thread);
		Thread thead9 = new Thread(thread);
		Thread thead10 = new Thread(thread);
		thead1.start();
		thead2.start();
		thead3.start();
		thead4.start();
		thead5.start();
		thead6.start();
		thead7.start();
		thead8.start();
		thead9.start();
		thead10.start();
	}
}

输出

线程[Thread-2]执行count=10
线程[Thread-3]执行count=9
线程[Thread-1]执行count=10
线程[Thread-4]执行count=8
线程[Thread-5]执行count=7
线程[Thread-6]执行count=6
线程[Thread-7]执行count=5
线程[Thread-8]执行count=4
线程[Thread-9]执行count=3
线程[Thread-10]执行count=2

共享变量,使用synchronized使得线程安全

Tools.java
package com.gxx.threads.study.test5;
 
/** 
 * 工具类
 * @author Gxx
 */
public class Tools {
	/**
	 * 计数
	 */
	int count = 10;
 
	/**
	 * 打印count
	 * @throws Exception
	 */
	public synchronized void printCount() {
		try {
			count--;
			/**
			 * 睡眠1秒
			 */
			Thread.sleep(1000);
			System.out.println("线程[" + Thread.currentThread().getName() + "]执行count=" + count);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
MyThread.java
package com.gxx.threads.study.test5;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 工具类
	 */
	Tools tools;
 
	/**
	 * 构造方法
	 * @param tools
	 */
	public MyThread(Tools tools){
		this.tools = tools;
	}
 
	/**
	 * 覆盖父类的run方法
	 */
	@Override
	public void run() {
		tools.printCount();
	}
}
Test.java
package com.gxx.threads.study.test5;
 
/**
 * 测试类-共享变量,使用synchronized使得线程安全
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		Tools tools = new Tools();
		/**
		 * 共用同一个tools
		 */
		MyThread thread1 = new MyThread(tools);
		MyThread thread2 = new MyThread(tools);
		thread1.start();
		thread2.start();
	}
}

输出

线程[Thread-0]执行count=9
线程[Thread-1]执行count=8

count--和System.out.println()

注意:

println.java
public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

getId()、isAlive()和sleep()

MyThread.java
package com.gxx.threads.study.test6;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("线程 run 开始 时间=" + System.currentTimeMillis());
		System.out.println("线程 getId()=" + this.getId());
		System.out.println("线程 run 中 isAlive()=" + this.isAlive());
		System.out.println("线程 run 结束 时间=" + System.currentTimeMillis());
	}
}
Test.java
package com.gxx.threads.study.test6;
 
/**
 * 测试类-测试getId()、isAlive()和sleep()
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main主线程 开始 时间=" + System.currentTimeMillis());
		System.out.println("main主线程 getId()=" + Thread.currentThread().getId());
		MyThread thread = new MyThread();
		System.out.println("线程 start前 isAlive()=" + thread.isAlive());
		thread.start();
		System.out.println("线程 start后 isAlive()=" + thread.isAlive());
		System.out.println("main主线程 结束 时间=" + System.currentTimeMillis());
 
		try {
			Thread.sleep(1000);
			System.out.println("main主线程 sleep(1秒)后 线程 isAlive=" + thread.isAlive());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

输出

main主线程 开始 时间=1464492826078
main主线程 getId()=1
线程 start前 isAlive()=false
线程 start后 isAlive()=true
main主线程 结束 时间=1464492826080
线程 run 开始 时间=1464492826080
线程 getId()=8
线程 run 中 isAlive()=true
线程 run 结束 时间=1464492826080
main主线程 sleep(1秒)后 线程 isAlive=false

停止线程

interrupt、isInterrupted、interrupted

给线程打个中断的标记,线程继续运行

判断线程是否有中断的标记,如果有返回true,多次调用都返回true

静态方法,Thread.interrupted(),判断当前线程是否有中断的标记,如果有返回true,并清空该标记,下次再执行,则返回false

MyThread.java
package com.gxx.threads.study.test7;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("run 开始");
		this.interrupt();
		System.out.println("执行this.interrupt()只是打个线程中断标记,线程还是继续往下走");
		System.out.println("this.isInterrupted()=" + this.isInterrupted());
		System.out.println("this.isInterrupted()=" + this.isInterrupted());
		System.out.println("执行静态方法Thread.interrupted()=" + Thread.interrupted() + "后清空中断状态");
		System.out.println("再执行静态方法Thread.interrupted()=" + Thread.interrupted());
		System.out.println("this.isInterrupted()=" + this.isInterrupted());
		System.out.println("run 结束");
	}
}
Test.java
package com.gxx.threads.study.test7;
 
/**
 * 测试类-测试interrupt、isInterrupted、interrupted
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MyThread thread = new MyThread();
		thread.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
run 开始
执行this.interrupt()只是打个线程中断标记,线程还是继续往下走
this.isInterrupted()=true
this.isInterrupted()=true
执行静态方法Thread.interrupted()=true后清空中断状态
再执行静态方法Thread.interrupted()=false
this.isInterrupted()=false
run 结束

测试线程interrupt()然后sleep()

先中断,再睡眠,会抛出异常

MyThread.java
package com.gxx.threads.study.test8;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("run 开始");
		System.out.println("run 准备执行sleep(1000) 睡眠1秒");
		try {
			sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("run 结束");
	}
}
Test.java
package com.gxx.threads.study.test8;
 
/**
 * 测试类-测试线程interrupt()然后sleep()
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MyThread thread = new MyThread();
		thread.start();
		thread.interrupt();
		System.out.println("main 执行thread.interrupt(),给thread打个中断标记");
		System.out.println("main 结束");
	}
}

输出

main 开始
main 执行thread.interrupt(),给thread打个中断标记
main 结束
run 开始
run 准备执行sleep(1000) 睡眠1秒
run 结束
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.gxx.threads.study.test8.MyThread.run(MyThread.java:16)

测试线程sleep()然后interrupt()

在睡眠的过程中,中断,会抛出异常

MyThread.java
package com.gxx.threads.study.test9;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("run 开始");
		System.out.println("run 准备执行sleep(10000) 睡眠10秒");
		try {
			sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("run 结束");
	}
}
Test.java
package com.gxx.threads.study.test9;
 
/**
 * 测试类-测试线程sleep()然后interrupt()
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MyThread thread = new MyThread();
		thread.start();
		System.out.println("main 睡眠1秒");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("main 执行thread.interrupt(),给thread打个中断标记");
		thread.interrupt();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 睡眠1秒
run 开始
run 准备执行sleep(10000) 睡眠10秒
main 执行thread.interrupt(),给thread打个中断标记
main 结束
run 结束
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.gxx.threads.study.test9.MyThread.run(MyThread.java:16)

抛出异常或者return来停止线程

建议使用这两种方式

if(this.isInterrupted()){
	throw new Exception();
}
if(this.interrupted()){
	return;
}

stop()暴力停止,@Deprecated作废

不建议使用,因为stop()停止线程有可能使一些清理性的工作得不到完成。另外会对锁定的对象强制解锁,导致数据得不到同步的处理,出现数据不一致的问题!比如:

synchronized public void setUserNameAndPassword(String userName, String password){
	this.userName = userName;
	Thread.sleep(1000000);//正好外面执行stop(),导致数据不一致
	this.password = password;
}

suspend()和resume()

如果synchronized方法执行一半,不会释放锁,一直卡着,比如线程内System.out.println()打印一半(打印数据,再打印换行,有synchronized代码块)暂停了,其他地方调System.out.println()都会一直卡着,输出不到控台;@Deprecated作废,不建议使用

从暂停的地方恢复,程序往下走,但是有时间差,可能会有脏数据;@Deprecated作废,不建议使用

MyThread.java
package com.gxx.threads.study.test10;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 标志
	 */
	boolean flag = false;
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("run 开始");
		System.out.println("run 打印flag=" + flag);
		System.out.println("run 执行this.suspend(),并等待resume()");
		this.suspend();
		System.out.println("run 线程被恢复");
		System.out.println("run 再次打印flag=" + flag);
		System.out.println("run 结束");
	}
}
Test.java
package com.gxx.threads.study.test10;
 
/**
 * 测试类-测试线程suspend()和resume(),产生脏数据
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MyThread thread = new MyThread();
		thread.start();
		System.out.println("main 睡眠1秒");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("main 睡眠1秒后 修改thread.flag = true");
		thread.flag = true;
		System.out.println("main 执行thread.resume()");
		thread.resume();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 睡眠1秒
run 开始
run 打印flag=false
run 执行this.suspend(),并等待resume()
main 睡眠1秒后 修改thread.flag = true
main 执行thread.resume()
main 结束
run 线程被恢复
run 再次打印flag=true
run 结束

yield()

让出CPU资源,但是有可能让出又马上获得CPU时间片。

MyThread.java
package com.gxx.threads.study.test11;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 计数
	 */
	int count = 10;
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		while(count > 0){
			System.out.println("[" + this.getName() + "] count=" + count);
			count --;
			this.yield();//让出CPU
		}
	}
}
Test.java
package com.gxx.threads.study.test11;
 
/**
 * 测试类-测试线程yield()让出CPU
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MyThread threadA = new MyThread();
		threadA.setName("线程A");
		threadA.start();
		MyThread threadB = new MyThread();
		threadB.setName("线程B");
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A] count=10
[线程B] count=10
[线程A] count=9
[线程B] count=9
[线程A] count=8
[线程B] count=8
[线程A] count=7
[线程B] count=7
[线程A] count=6
[线程B] count=6
[线程A] count=5
[线程B] count=5
[线程A] count=4
[线程B] count=4
[线程A] count=3
[线程B] count=3
[线程A] count=2
[线程B] count=2
[线程A] count=1
[线程B] count=1

线程的优先级

MyThread.java
package com.gxx.threads.study.test12;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		System.out.println("run 开始");
		System.out.println("线程[" + Thread.currentThread().getName() + "]优先级[继承][" + Thread.currentThread().getPriority() + "]");
		System.out.println("run 结束");
	}
}
Test.java
package com.gxx.threads.study.test12;
 
/**
 * 测试类-测试线程线程优先级的常量,默认值,范围和继承性
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("===线程优先级常量=开始======");
		System.out.println("线程优先级MIN_PRIORITY=" + Thread.MIN_PRIORITY);
		System.out.println("线程优先级NORM_PRIORITY=" + Thread.NORM_PRIORITY);
		System.out.println("线程优先级MAX_PRIORITY=" + Thread.MAX_PRIORITY);
		System.out.println("===线程优先级常量=结束======");
 
		System.out.println("main 开始");
		System.out.println("线程[" + Thread.currentThread().getName() + "]优先级[默认][" + Thread.currentThread().getPriority() + "]");
 
		try{
			System.out.println("=========");
			System.out.println("线程[" + Thread.currentThread().getName() + "]优先级[设置][11]");
			Thread.currentThread().setPriority(11);
		} catch (Exception e){
			System.out.println("设置[11]失败!");
			System.out.println("线程优先级设置范围在[" + Thread.MIN_PRIORITY + "]~[" + Thread.MAX_PRIORITY + "]");
			System.out.println("=========");
		}
 
		/**
		 * range MIN_PRIORITY to MAX_PRIORITY
		 * 设置线程优先级必须在[MIN_PRIORITY,MAX_PRIORITY]也就是[1,10]
		 */
		Thread.currentThread().setPriority(8);
 
		System.out.println("线程[" + Thread.currentThread().getName() + "]优先级[设置][" + Thread.currentThread().getPriority() + "]");
 
		MyThread thread = new MyThread();
		thread.setName("线程A");
		thread.start();
		System.out.println("线程[" + Thread.currentThread().getName() + "]创建线程[" + thread.getName() + "]");
		System.out.println("main 结束");
	}
}

输出

===线程优先级常量=开始======
线程优先级MIN_PRIORITY=1
线程优先级NORM_PRIORITY=5
线程优先级MAX_PRIORITY=10
===线程优先级常量=结束======
main 开始
线程[main]优先级[默认][5]
=========
线程[main]优先级[设置][11]
设置[11]失败!
线程优先级设置范围在[1]~[10]
=========
线程[main]优先级[设置][8]
线程[main]创建线程[线程A]
main 结束
run 开始
线程[线程A]优先级[继承][8]
run 结束
MyThread.java
package com.gxx.threads.study.test13;
 
import java.util.Date;
import java.util.Random;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 构造方法
	 * @param name 线程名字
	 * @param priority 优先级
	 */
	public MyThread(String name, int priority) {
		this.setName(name);//设置线程名字
		this.setPriority(priority);//设置优先级
	}
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		long startTime = new Date().getTime();
		for(int i=0; i<10000000; i++){
			new Random().nextInt();
		}
		long endTime = new Date().getTime();
		String name = "[高优先级]";
		if(this.getPriority() <= 5){
			name = "[低优先级]";
		}
		System.out.println(name + "线程[" + Thread.currentThread().getName() + "]运行结束,耗时[" + (endTime - startTime) + "]毫秒~");
	}
}
Test.java
package com.gxx.threads.study.test13;
 
/**
 * 测试类-测试线程优先级的规则性,随机性,速度
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MyThread thread1 = new MyThread("线程1", 10);
		MyThread thread2 = new MyThread("线程2", 1);
		MyThread thread3 = new MyThread("线程3", 10);
		MyThread thread4 = new MyThread("线程4", 1);
		MyThread thread5 = new MyThread("线程5", 10);
		MyThread thread6 = new MyThread("线程6", 1);
		MyThread thread7 = new MyThread("线程7", 10);
		MyThread thread8 = new MyThread("线程8", 1);
		MyThread thread9 = new MyThread("线程9", 10);
		MyThread thread10 = new MyThread("线程10", 1);
 
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		thread6.start();
		thread7.start();
		thread8.start();
		thread9.start();
		thread10.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[高优先级]线程[线程1]运行结束,耗时[8021]毫秒~
[高优先级]线程[线程9]运行结束,耗时[8135]毫秒~
[低优先级]线程[线程6]运行结束,耗时[8168]毫秒~
[高优先级]线程[线程3]运行结束,耗时[8167]毫秒~
[低优先级]线程[线程2]运行结束,耗时[8167]毫秒~
[高优先级]线程[线程7]运行结束,耗时[8174]毫秒~
[低优先级]线程[线程10]运行结束,耗时[8185]毫秒~
[低优先级]线程[线程8]运行结束,耗时[8195]毫秒~
[低优先级]线程[线程4]运行结束,耗时[8198]毫秒~
[高优先级]线程[线程5]运行结束,耗时[8205]毫秒~

守护线程

守护线程比如垃圾回收器GC,当没有非守护线程的时候,守护线程没有意义,会自动停止!

MyThread.java
package com.gxx.threads.study.test14;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 计数
	 */
	int count = 0;
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("[" + this.getName() + "][守护线程]打印count=" + (++count));
		}
	}
}
Test.java
package com.gxx.threads.study.test14;
 
/**
 * 测试类-测试守护线程
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("[main][非守护线程] 开始");
		MyThread thread = new MyThread();
		thread.setName("Thead");
		System.out.println("[线程][" + thread.getName() + "]默认为" + (thread.isDaemon()?"[true][守护线程]":"[false][非守护线程]"));
		System.out.println("[线程][" + thread.getName() + "]设置为[true][守护线程]");
		thread.setDaemon(true);
		thread.start();
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("[main][非守护线程] 结束,则[守护线程]也自动结束");
	}
}

输出

[main][非守护线程] 开始
[线程][Thead]默认为[false][非守护线程]
[线程][Thead]设置为[true][守护线程]
[Thead][守护线程]打印count=1
[Thead][守护线程]打印count=2
[Thead][守护线程]打印count=3
[Thead][守护线程]打印count=4
[Thead][守护线程]打印count=5
[Thead][守护线程]打印count=6
[Thead][守护线程]打印count=7
[Thead][守护线程]打印count=8
[Thead][守护线程]打印count=9
[main][非守护线程] 结束,则[守护线程]也自动结束

对象及变量的并发访问

synchronized同步方法

方法内变量为线程安全

NumProcess.java
package com.gxx.threads.study.test15;
 
/** 
 * 数字处理器
 * @author Gxx
 */
public class NumProcess {
	/**
	 * 处理逻辑
	 */
	public void process(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入process~");
		/**
		 * 方法内变量
		 */
		int num;
		/**
		 * 根据线程名称走不同分支
		 */
		if(Thread.currentThread().getName().equals("线程A")){
			num = 100;
			try {
				Thread.sleep(2000);//睡眠2秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			num = 200;
		}
		System.out.println("[" + Thread.currentThread().getName() + "] num=" + num);
	}
}
MyThead.java
package com.gxx.threads.study.test15;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 数字处理器
	 */
	NumProcess numProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param numProcess
	 */
	public MyThread(String name, NumProcess numProcess) {
		this.setName(name);
		this.numProcess = numProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		numProcess.process();
	}
}
Test.java
package com.gxx.threads.study.test15;
 
/**
 * 测试类-测试方法内变量并发访问
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		NumProcess numProcess = new NumProcess();
		MyThread threadA = new MyThread("线程A", numProcess);
		MyThread threadB = new MyThread("线程B", numProcess);
		threadA.start();
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A]进入process~
[线程B]进入process~
[线程B] num=200
[线程A] num=100

实例变量非线程安全

NumProcess.java
package com.gxx.threads.study.test16;
 
/** 
 * 数字处理器
 * @author Gxx
 */
public class NumProcess {
	/**
	 * 实例变量
	 */
	int num;
	/**
	 * 处理逻辑
	 */
	public void process(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入process~");
		/**
		 * 根据线程名称走不同分支
		 */
		if(Thread.currentThread().getName().equals("线程A")){
			num = 100;
			try {
				Thread.sleep(2000);//睡眠2秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			num = 200;
		}
		System.out.println("[" + Thread.currentThread().getName() + "] num=" + num);
	}
}
MyThead.java
package com.gxx.threads.study.test16;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 数字处理器
	 */
	NumProcess numProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param numProcess
	 */
	public MyThread(String name, NumProcess numProcess) {
		this.setName(name);
		this.numProcess = numProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		numProcess.process();
	}
}
Test.java
package com.gxx.threads.study.test16;
 
/**
 * 测试类-测试实例变量并发访问
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		NumProcess numProcess = new NumProcess();
		MyThread threadA = new MyThread("线程A", numProcess);
		MyThread threadB = new MyThread("线程B", numProcess);
		threadA.start();
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A]进入process~
[线程B]进入process~
[线程B] num=200
[线程A] num=200

实例变量非线程安全,synchronized同步

NumProcess.java
package com.gxx.threads.study.test17;
 
/** 
 * 数字处理器
 * @author Gxx
 */
public class NumProcess {
	/**
	 * 实例变量
	 */
	int num;
	/**
	 * 处理逻辑
	 */
	public synchronized void process(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入process~");
		/**
		 * 根据线程名称走不同分支
		 */
		if(Thread.currentThread().getName().equals("线程A")){
			num = 100;
			try {
				Thread.sleep(2000);//睡眠2秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			num = 200;
		}
		System.out.println("[" + Thread.currentThread().getName() + "] num=" + num);
	}
}
MyThead.java
package com.gxx.threads.study.test17;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 数字处理器
	 */
	NumProcess numProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param numProcess
	 */
	public MyThread(String name, NumProcess numProcess) {
		this.setName(name);
		this.numProcess = numProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		numProcess.process();
	}
}
Test.java
package com.gxx.threads.study.test17;
 
/**
 * 测试类-测试实例变量并发访问,synchronized同步
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		NumProcess numProcess = new NumProcess();
		MyThread threadA = new MyThread("线程A", numProcess);
		MyThread threadB = new MyThread("线程B", numProcess);
		threadA.start();
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A]进入process~
[线程A] num=100
[线程B]进入process~
[线程B] num=200

多个对象多个锁

NumProcess.java
package com.gxx.threads.study.test18;
 
/** 
 * 数字处理器
 * @author Gxx
 */
public class NumProcess {
	/**
	 * 实例变量
	 */
	int num;
	/**
	 * 处理逻辑
	 */
	public synchronized void process(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入process~");
		/**
		 * 根据线程名称走不同分支
		 */
		if(Thread.currentThread().getName().equals("线程A")){
			num = 100;
			try {
				Thread.sleep(2000);//睡眠2秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			num = 200;
		}
		System.out.println("[" + Thread.currentThread().getName() + "] num=" + num);
	}
}
MyThead.java
package com.gxx.threads.study.test18;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 数字处理器
	 */
	NumProcess numProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param numProcess
	 */
	public MyThread(String name, NumProcess numProcess) {
		this.setName(name);
		this.numProcess = numProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		numProcess.process();
	}
}
Test.java
package com.gxx.threads.study.test18;
 
/**
 * 测试类-测试多个对象多个锁
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		NumProcess numProcess1 = new NumProcess();
		MyThread threadA = new MyThread("线程A", numProcess1);
		NumProcess numProcess2 = new NumProcess();
		MyThread threadB = new MyThread("线程B", numProcess2);
		threadA.start();
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A]进入process~
[线程B]进入process~
[线程B] num=200
[线程A] num=100

synchronized方法与锁对象

MethodProcess.java
package com.gxx.threads.study.test19;
 
/** 
 * 方法处理器
 * @author Gxx
 */
public class MethodProcess {
	/**
	 * 方法A
	 */
	public synchronized void methodA(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodA~");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("[" + Thread.currentThread().getName() + "]methodA结束");
	}
 
	/**
	 * 方法B
	 */
	public void methodB(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodB~");
		System.out.println("[" + Thread.currentThread().getName() + "]methodB结束");
	}
}
MyThead.java
package com.gxx.threads.study.test19;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 方法处理器
	 */
	MethodProcess methodProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param methodProcess
	 */
	public MyThread(String name, MethodProcess methodProcess) {
		this.setName(name);
		this.methodProcess = methodProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		if("线程A".equals(this.getName())){
			methodProcess.methodA();
		} else {
			methodProcess.methodB();
		}
	}
}
Test.java
package com.gxx.threads.study.test19;
 
/**
 * 测试类-测试synchronized方法与锁对象
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MethodProcess methodProcess = new MethodProcess();
		MyThread threadA = new MyThread("线程A", methodProcess);
		MyThread threadB = new MyThread("线程B", methodProcess);
		threadA.start();
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A]进入methodA~
[线程B]进入methodB~
[线程B]methodB结束
[线程A]methodA结束
MethodProcess.java
package com.gxx.threads.study.test20;
 
/** 
 * 方法处理器
 * @author Gxx
 */
public class MethodProcess {
	/**
	 * 方法A
	 */
	public synchronized void methodA(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodA~");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("[" + Thread.currentThread().getName() + "]methodA结束");
	}
 
	/**
	 * 方法B
	 */
	public synchronized void methodB(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodB~");
		System.out.println("[" + Thread.currentThread().getName() + "]methodB结束");
	}
}
MyThead.java
package com.gxx.threads.study.test20;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 方法处理器
	 */
	MethodProcess methodProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param methodProcess
	 */
	public MyThread(String name, MethodProcess methodProcess) {
		this.setName(name);
		this.methodProcess = methodProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		if("线程A".equals(this.getName())){
			methodProcess.methodA();
		} else {
			methodProcess.methodB();
		}
	}
}
Test.java
package com.gxx.threads.study.test20;
 
/**
 * 测试类-测试synchronized方法与锁对象
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MethodProcess methodProcess = new MethodProcess();
		MyThread threadA = new MyThread("线程A", methodProcess);
		MyThread threadB = new MyThread("线程B", methodProcess);
		threadA.start();
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A]进入methodA~
[线程A]methodA结束
[线程B]进入methodB~
[线程B]methodB结束

synchronized锁重入与异常释放锁

MethodProcess.java
package com.gxx.threads.study.test21;
 
/** 
 * 方法处理器
 * @author Gxx
 */
public class MethodProcess extends MethodProcessParent {
	/**
	 * 方法A
	 */
	public synchronized void methodA(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodA~");
		methodB();
	}
 
	/**
	 * 方法B
	 */
	public synchronized void methodB(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodB~");
		methodC();
	}
 
	/**
	 * 方法C
	 */
	public synchronized void methodC(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodC~");
		super.methodD();
	}
}
MethodProcessParent.java
package com.gxx.threads.study.test21;
 
/** 
 * 方法处理器
 * @author Gxx
 */
public class MethodProcessParent {
	/**
	 * 计数
	 */
	int count = 0;
 
	/**
	 * 方法D
	 */
	public synchronized void methodD(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入methodD~");
		while (true) {
			System.out.println("[" + Thread.currentThread().getName() + "]打印count=" + count);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if(++count == 5){
				count = 0;
				throw new RuntimeException("手动抛出异常~");
			}
		}
	}
}
MyThead.java
package com.gxx.threads.study.test21;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 方法处理器
	 */
	MethodProcess methodProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param methodProcess
	 */
	public MyThread(String name, MethodProcess methodProcess) {
		this.setName(name);
		this.methodProcess = methodProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		methodProcess.methodA();
	}
}
Test.java
package com.gxx.threads.study.test21;
 
/**
 * 测试类-测试synchronized锁重入
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MethodProcess methodProcess = new MethodProcess();
		MyThread threadA = new MyThread("线程A", methodProcess);
		threadA.start();
		MyThread threadB = new MyThread("线程B", methodProcess);
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程A]进入methodA~
[线程A]进入methodB~
[线程A]进入methodC~
[线程A]进入methodD~
[线程A]打印count=0
[线程A]打印count=1
[线程A]打印count=2
[线程A]打印count=3
[线程A]打印count=4
[线程B]进入methodA~
Exception in thread "线程A" java.lang.RuntimeException: 手动抛出异常~
	at com.gxx.threads.study.test21.MethodProcessParent.methodD(MethodProcessParent.java:27)
	at com.gxx.threads.study.test21.MethodProcess.methodC(MethodProcess.java:29)
	at com.gxx.threads.study.test21.MethodProcess.methodB(MethodProcess.java:21)
	at com.gxx.threads.study.test21.MethodProcess.methodA(MethodProcess.java:13)
	at com.gxx.threads.study.test21.MyThread.run(MyThread.java:28)
[线程B]进入methodB~
[线程B]进入methodC~
[线程B]进入methodD~
[线程B]打印count=0
[线程B]打印count=1
[线程B]打印count=2
[线程B]打印count=3
[线程B]打印count=4
Exception in thread "线程B" java.lang.RuntimeException: 手动抛出异常~
	at com.gxx.threads.study.test21.MethodProcessParent.methodD(MethodProcessParent.java:27)
	at com.gxx.threads.study.test21.MethodProcess.methodC(MethodProcess.java:29)
	at com.gxx.threads.study.test21.MethodProcess.methodB(MethodProcess.java:21)
	at com.gxx.threads.study.test21.MethodProcess.methodA(MethodProcess.java:13)
	at com.gxx.threads.study.test21.MyThread.run(MyThread.java:28)

同步不具有继承性

MethodProcess.java
package com.gxx.threads.study.test22;
 
/** 
 * 方法处理器
 * @author Gxx
 */
public class MethodProcess extends MethodProcessParent {
	/**
	 * 处理
	 */
	public void process(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入process~");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("[" + Thread.currentThread().getName() + "]process结束");
	}
}
MethodProcessParent.java
package com.gxx.threads.study.test22;
 
/** 
 * 方法处理器
 * @author Gxx
 */
public class MethodProcessParent {
	/**
	 * 处理
	 */
	public synchronized void process(){
		System.out.println("[" + Thread.currentThread().getName() + "]进入process~");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("[" + Thread.currentThread().getName() + "]process结束");
	}
}
MyThead.java
package com.gxx.threads.study.test22;
 
/** 
 * 自定义线程类
 * @author Gxx
 */
public class MyThread extends Thread {
	/**
	 * 方法处理器
	 */
	MethodProcess methodProcess;
 
	/**
	 * 构造方法
	 * @param name
	 * @param methodProcess
	 */
	public MyThread(String name, MethodProcess methodProcess) {
		this.setName(name);
		this.methodProcess = methodProcess;
	}
 
	/**
	 * 覆盖run方法
	 */
	@Override
	public void run() {
		methodProcess.process();
	}
}
Test.java
package com.gxx.threads.study.test22;
 
/**
 * 测试类-测试同步不具有继承性
 * @author Gxx
 */
public class Test {
	/**
	 * main方法
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("main 开始");
		MethodProcess methodProcess = new MethodProcess();
		MyThread threadA = new MyThread("线程A", methodProcess);
		MyThread threadB = new MyThread("线程B", methodProcess);
		threadA.start();
		threadB.start();
		System.out.println("main 结束");
	}
}

输出

main 开始
main 结束
[线程B]进入process~
[线程A]进入process~
[线程B]process结束
[线程A]process结束