LZ看的是高洪岩的《Java多线程编程核心技术》和《Java并发编程核心方法与框架》,都两本书都是偏入门的书籍,《Java并发编程的艺术》和《Java并发编程实战》是业内公认的好书
实现多线程编程的方式主要有两种,继承Thread类和实现Runnable接口
线程启动顺序与start()方法执行顺序无关
共享自定义线程类中的实例变量
public class MyThread extends Thread{
private int count = 3;
@Override
public synchronized void run() {
count--;
System.out.println(this.currentThread().getName() + count);
}
}
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread a = new Thread(myThread, "a");
Thread b = new Thread(myThread, "b");
Thread c = new Thread(myThread, "c");
//a2
//b1
//c0
a.start();
b.start();
c.start();
}
}
有3种方法可以停止当前运行的线程
static boolean interrupted()
boolean isInterrupted()
interrupted() Tests whether the current thread has been interrupted,执行后具有将状态标志清除为false的功能
isInterrupted() Tests whether this thread has been interrupted,不清除状态标志
public class Run {
public static void main(String[] args) {
Thread.currentThread().interrupt();
//是否停止? true
System.out.println("是否停止? " + Thread.interrupted());
//是否停止? false
System.out.println("是否停止? " + Thread.interrupted());
}
}
public class MyThread extends Thread{
@Override
public synchronized void run() {
for (int i=0; i<5000; i++) {
System.out.println(i);
}
}
}
public class Run2 {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(20);
myThread.interrupt();
System.out.println("是否停止? " + myThread.isInterrupted());
System.out.println("是否停止? " + myThread.isInterrupted());
}
}
对线程调用interrupt,并不能直接停止线程的运行,会等run方法运行完毕
interrupt+异常停止线程
public class MyThread extends Thread{
@Override
public void run() {
for (int i=0; i<50000; i++) {
if (this.isInterrupted()) {
System.out.println("中断线程");
break;
}
System.out.println(i);
}
System.out.println("for循环语句后");
}
}
public class MyThread extends Thread{
@Override
public void run() {
try {
for (int i=0; i<50000; i++) {
if (this.isInterrupted()) {
System.out.println("中断线程");
throw new InterruptedException();
}
System.out.println(i);
}
System.out.println("for循环语句后");
} catch (InterruptedException e) {
System.out.println("进入catch方法");
}
}
}
先调用sleep,后调用interrupt或者先调用interrupt再调用sleep会产生异常
interrupt+return停止异常
public class MyThread extends Thread{
@Override
public void run() {
while (true) {
if (this.isInterrupted()) {
System.out.println("停止了");
return;
}
System.out.println(System.currentTimeMillis());
}
}
}
yield方法的作用是放弃当前的CPU资源,让其他任务去占用CPU执行时间。但放弃时间不确定,有可能刚放弃,马上又获得CPU时间片
public class MyThread extends Thread{
@Override
public void run() {
long beginTime = System.currentTimeMillis();
for (int i=0; i<500000; i++) {
//Thread.yield();
}
long endTime = System.currentTimeMillis();
System.out.println("运行时间" + (endTime - beginTime));
}
}
未打开注释:运行时间3
打开注释:运行时间59
如果多个线程共同访问1个对象中的实例变量,则有可能出现“非线程安全”问题
public class SelfPrivateNum {
private int num = 0;
public void add(String userName) {
try {
if (userName.equals("a")) {
num = 100;
Thread.sleep(1000);
} else if (userName.equals("b")) {
num = 200;
}
System.out.println(userName + " " + num);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MyThreadA extends Thread{
private SelfPrivateNum selfPrivateNum;
public MyThreadA(SelfPrivateNum selfPrivateNum) {
this.selfPrivateNum = selfPrivateNum;
}
@Override
public void run() {
selfPrivateNum.add("a");
}
}
MyThreadB是在run方法中调用selfPrivateNum.add(“b”),其他和MyThreadA都一样
public class Run {
public static void main(String[] args) {
SelfPrivateNum selfPrivateNum = new SelfPrivateNum();
MyThreadA myThreadA = new MyThreadA(selfPrivateNum);
//b 200
myThreadA.start();
//a 200
MyThreadB myThreadB = new MyThreadB(selfPrivateNum);
myThreadB.start();
}
}
调用用关键字synchronized声明的方法一定是排队运行的,但却可以异步调用非synchronized类型的方法
关键字synchronized具有锁重入的功能,当一个线程得到一个对象锁后,可以再次请求得到对象锁。因此在一个synchronized方法内部调用本类的synchronized方法时,是可以得到锁的
public class Service {
public synchronized void service1() {
System.out.println("service1");
service2();
}
public synchronized void service2() {
System.out.println("service2");
}
}
public class MyThread extends Thread{
@Override
public void run() {
Service service = new Service();
service.service1();
}
}
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
//service1
//service2
myThread.start();
}
}
当存在继承关系时,子类可以通过“可重入锁”调用父类的同步方法
当出现异常时,锁被自动释放,子类从父类中继承的同步方法不具有同步性,必须自己加上synchronized
解决异步死循环
public class RunThread extends Thread{
private boolean isRunning = true;
public boolean isRunning() {
return isRunning;
}
public void setRunning(boolean running) {
isRunning = running;
}
@Override
public void run() {
System.out.println("进入run方法");
while (isRunning) {
}
System.out.println("线程被停止");
}
}
public class Run {
public static void main(String[] args) {
try {
RunThread thread = new RunThread();
thread.start();
Thread.sleep(1000);
thread.setRunning(false);
System.out.println("已经赋值为false");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程被停止这句话始终没有被输出,是因为private boolean isRunning = true;存在于公共堆栈及线程的私有堆栈中,线程一直在私有堆栈中取得isRunning的值为true。而代码thread.setRunning(false);虽然被执行,更新的确实公共堆栈中的isRunning变量值false,所以一直就是死循环状态
private volatile boolean isRunning = true;
将isRunning用volatile修饰,结果如图
是因为使用volatile关键字,强制从公共内存中读取变量的值
synchronized和volatile的对比
volatile非原子特性
public class MyThread extends Thread{
public static volatile int count;
private static void addCount() {
for (int i=0; i<100; i++) {
count++;
}
System.out.println(count);
}
@Override
public void run() {
addCount();
}
}
public class Run {
public static void main(String[] args) {
MyThread[] myThreads = new MyThread[100];
for (int i=0; i<100; i++) {
myThreads[i] = new MyThread();
}
for (int i=0; i<100; i++) {
myThreads[i].start();
}
}
}
如果能保证原子性,则最后输出应该是10000
使用关键字volatile时出现非线程安全的原因
变量在内存中工作的过程如下
除了在i++操作时使用synchronized关键字实现同步外,还可以使用AtomicInteger原子类进行实现
public class Service {
private boolean isContinueRun = true;
public void runMethod() {
while (isContinueRun) {
}
System.out.println("已经停下来了");
}
public void stopMethod() {
isContinueRun = false;
}
}
public class ThreadA extends Thread{
private Service service;
public ThreadA(Service service) {
this.service = service;
}
@Override
public void run() {
service.runMethod();
}
}
public class ThreadB extends Thread{
private Service service;
public ThreadB(Service service) {
this.service = service;
}
@Override
public void run() {
service.stopMethod();
}
}
public class Run {
public static void main(String[] args) {
try {
Service service = new Service();
ThreadA a = new ThreadA(service);
ThreadB b = new ThreadB(service);
a.start();
Thread.sleep(1000);
b.start();
System.out.println("已经发出停止命令");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
得到这个结果时各线程间的数据值没有可视性造成的,而关键字synchronized可以具有可视性
public class Service {
private boolean isContinueRun = true;
public void runMethod() {
while (isContinueRun) {
String anyString = new String();
synchronized (anyString) {
}
}
System.out.println("已经停下来了");
}
public void stopMethod() {
isContinueRun = false;
}
}
wait,notify,notifyAll都是Object类的方法,方法wait和notify要在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的对象级别锁。在执行notify()方法后,当前线程不会马上释放该对象锁,呈wait状态的线程也并不能马上获得该对象锁,要等到notify()方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁,而呈wait状态所在的线程才可以获取该对象锁。
public class Test1 {
public static void main(String[] args) {
try {
String newString = new String("");
newString.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MyThread1 extends Thread{
private Object lock;
public MyThread1(Object lock) {
this.lock = lock;
}
@Override
public void run() {
try {
synchronized (lock) {
System.out.println("开始 wait time = " + System.currentTimeMillis());
lock.wait();
System.out.println("结束 wait time = " + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MyThread2 extends Thread{
private Object lock;
public MyThread2(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
System.out.println("开始 notify time = " + System.currentTimeMillis());
lock.notify();
System.out.println("结束 nofity time = " + System.currentTimeMillis());
}
}
}
public class Run {
public static void main(String[] args) {
try {
Object obj = new Object();
MyThread1 myThread1 = new MyThread1(obj);
myThread1.start();
Thread.sleep(3000);
MyThread2 myThread2 = new MyThread2(obj);
myThread2.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
wait被执行后,锁被自动释放,但执行完notify方法,锁却不自动释放,必须执行完notify方法所在的同步synchronized代码块后才释放锁
将MyThread2的代码更改如下,再次运行
public class MyThread2 extends Thread{
private Object lock;
public MyThread2(Object lock) {
this.lock = lock;
}
@Override
public void run() {
try {
synchronized (lock) {
System.out.println("开始 notify time = " + System.currentTimeMillis());
lock.notify();
Thread.sleep(3000);
System.out.println("结束 nofity time = " + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
调用notify一次只随机通知一个线程进行唤醒,为了唤醒所有线程,可以使用notifyAll方法
一生产一消费:操作值
public class P implements Runnable{
private String lock;
public P(String lock) {
this.lock = lock;
}
public void setValue() {
try {
synchronized (lock) {
if (!ValueObject.vlaue.equals("")) {
lock.wait();
}
String value = System.currentTimeMillis() + "";
System.out.println("set的值为 " + value);
ValueObject.vlaue = value;
lock.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
setValue();
}
}
}
public class C implements Runnable{
private String lock;
public C(String lock) {
this.lock = lock;
}
public void getValue() {
try {
synchronized (lock) {
if (ValueObject.vlaue.equals("")) {
lock.wait();
}
System.out.println("get的值为 " + ValueObject.vlaue);
ValueObject.vlaue = "";
lock.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
getValue();
}
}
}
public class ValueObject {
public static String vlaue = "";
}
public class Run {
public static void main(String[] args) {
String lock = new String("");
P p = new P(lock);
C c = new C(lock);
Thread threadp = new Thread(p);
Thread threadc = new Thread(c);
threadp.start();
threadc.start();
}
}
多生产多消费:操作值-假死
将上面代码中的P类和C类的if语句变为while语句
while (!ValueObject.vlaue.equals("")) {
lock.wait();
System.out.println(Thread.currentThread().getName() + " waiting");
}
Run更改如下
public class Run {
public static void main(String[] args) throws InterruptedException {
String lock = new String("");
P p = new P(lock);
C c = new C(lock);
Thread[] threadp = new Thread[2];
Thread[] threadc = new Thread[2];
for (int i=0; i<2; i++) {
threadp[i] = new Thread(p, "生产者" + (i + 1));
threadp[i].start();
threadc[i] = new Thread(c, "消费者" + (i + 1));
threadc[i].start();
}
Thread.sleep(5000);
Thread[] threads = new Thread[Thread.currentThread().getThreadGroup().activeCount()];
Thread.currentThread().getThreadGroup().enumerate(threads);
for (int i = 0; i < threads.length; i++) {
System.out.println("状态" + threads[i].getName() + " " + threads[i].getState());
}
}
}
有可能出现假死的情况,原因是有可能出现“生产者”唤醒“生产者”,或者“消费者”唤醒“消费者”的情况,解决的办法就是将P类和C类的notify改成notifyAll方法
public class MyThread extends Thread{
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println("子线程运行结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
//Thread.sleep();有时候我不知道子线程运行多长时间,所以不确定值
System.out.println("主线程运行完毕");
}
}
public class Run {
public static void main(String[] args) {
try {
MyThread myThread = new MyThread();
myThread.start();
myThread.join();
//Thread.sleep();有时候我不知道子线程运行多长时间,所以不确定值
System.out.println("主线程运行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在join过程中,如果当前线程对象被中断,则当前线程出现异常
join(long)中的参数时设定等待时间,超时就不再等待,方法join(long)的功能是在内部使用wait(long)方法来实现的,所以join(long)方法具有释放锁的特点,而Thread.sleep(long)方法却不释放锁
public class Tools {
public static ThreadLocal t1 = new ThreadLocal();
}
public class ThreadA extends Thread{
@Override
public void run() {
try {
for (int i=0; i<10; i++) {
Tools.t1.set("ThreadA " + i);
Thread.sleep(200);
System.out.println("ThreadA get value = " + Tools.t1.get());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
try {
ThreadA threadA = new ThreadA();
threadA.start();
for (int i=10; i<20; i++) {
Tools.t1.set("Main " + i);
Thread.sleep(200);
System.out.println("Main get value = " + Tools.t1.get());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MyService {
private Lock lock = new ReentrantLock();
public void testMethod() {
lock.lock();
for (int i=0; i<5; i++) {
System.out.println("Thread Name " + Thread.currentThread().getName() + " " + i);
}
lock.unlock();
}
}
public class MyThread extends Thread{
MyService myService;
public MyThread(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.testMethod();
}
}
public class Run {
public static void main(String[] args) {
MyService myService = new MyService();
MyThread myThread = new MyThread(myService);
MyThread myThread1 = new MyThread(myService);
myThread.start();
myThread1.start();
}
}
调用lock.lock()代码的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢
public class MyService {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void await() {
try {
//condition.await()方法调用之前调用lock.lock()代码获得同步监视器
lock.lock();
System.out.println("await时间为 " + System.currentTimeMillis());
condition.await();
} catch (InterruptedException e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signal() {
try {
lock.lock();
System.out.println("signal时间为 " + System.currentTimeMillis());
condition.signal();
} finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread{
private MyService myService;
public ThreadA(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.await();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyService myService = new MyService();
ThreadA threadA = new ThreadA(myService);
threadA.start();
Thread.sleep(3000);
myService.signal();
}
}
Object | Condition |
---|---|
wait | await |
wait(long timeout) | await(long time,TimeUnit unit) |
notify | signal |
notify | signalAll |
public class MyService {
private Lock lock = new ReentrantLock();
public Condition conditionA = lock.newCondition();
public Condition conditionB = lock.newCondition();
public void awaitA() {
try {
lock.lock();
System.out.println("begin awaitA 时间为" + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
conditionA.await();
System.out.println("end awaitA 时间为" + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitB() {
try {
lock.lock();
System.out.println("begin awaitB 时间为" + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
conditionB.await();
System.out.println("end awaitB 时间为" + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalAll_A() {
try {
lock.lock();
System.out.println("signalAll_A时间为 " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
conditionA.signalAll();
} finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread{
private MyService myService;
public ThreadA(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.awaitA();
}
}
public class Run {
public static void main(String[] args) {
try {
MyService myService = new MyService();
ThreadA threadA = new ThreadA(myService);
threadA.setName("A");
threadA.start();
ThreadB threadB = new ThreadB(myService);
threadB.setName("B");
threadB.start();
Thread.sleep(3000);
myService.signalAll_A();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadB线程调用MyService的awaitB方法
因为B线程没有结束,所以始终没有停止
Callable接口和Runnable接口的区别
线程池execute()和submit()的区别
生产者消费者模式-Java实现
[1]https://www.cnblogs.com/chentingk/p/6497107.html