Java并发编程1——线程状态、synchronized

以下内容主要总结自《Java多线程编程核心技术》,不定时补充更新。

一、线程的状态

Java中,线程的状态有以下6类:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED。各状态之间的关系可用下图表示:

二、常用方法介绍

1、thread.start()和thread.run()的区别

1 public static void main(String[] args) {
2         Thread t = new Thread();
3         t.start();
4         System.out.println("main end");
5     }

调用start()方法启动线程t,t线程的状态会从New -> Runnable,t线程和main主线程同时执行。

如果把t.start()改成t.run(),则是普通的调用方法,同步执行,System.out.println("main end")语句必须等t.run()方法执行完毕之后才能执行。

注意:t.run()方法不会改变线程t的状态,也就是说线程没有启动。

2、object.wait()和thread.sleep()的区别

1 private Object obj = new Object();
2 public void testMethod() throws InterruptedException {
3     synchronized (obj) {
4         obj.wait();
5         System.out.println("testMethod end");
6     }
7 }

wait()方法主要用在synchronized同步方法或者同步块中,意味着调用object.wait()之前必须先获取锁,调用wait()方法之后释放锁,线程进入waiting状态。常见用法如上所示。如果有其他线程通过调用object.notify()或者object.notifyAll()方法时,线程必须再次获取到obj锁,然后才能继续执行obj.wait()后的语句,即打印 "testMethod end"。obj.wait(timeout)方法类似,也需要先释放锁。

wait()方法是Object类的方法,而sleep(timeout)方法是Thread类的方法。线程调用sleep(timeout)方法,状态从runnable -> timed_waiting,但是不释放锁。

3、interrupt()方法

当线程调用interrupt()方法时,只是设置了线程的中断状态。 也就是说如果线程处于runnable或者blocked状态的时候,调用interrupt()方法并不会终止线程。于是,我想当然的理解如果线程处于waiting或者timed_waiting状态时,调用interrupt方法会抛出异常,从而终止线程。

然后发现错了。见如下代码:

 1 private ReentrantLock lock = new ReentrantLock();
 2 private Condition condition = lock.newCondition();
 3 public void testMethod() {
 4     try {
 5         lock.lock();
 6         System.out.println("wait begin");
 7         condition.awaitUninterruptibly();
 8         System.out.println("wait end");
 9     } finally {
10         lock.unlock();
11     }
12 }

condition.awaitUninterruptibly()方法不需要捕获InterruptedException异常,意味着如果线程通过调用awaitUninterruptibly从而使得线程状态为waiting,并不会因为调用interrupt()方法而中断。实际测试,线程状态不响应interrupt方法,只有通过condition.singal或者singalAll才能唤醒线程。

实际测试,wait(), wait(timeout), join(), sleep(timeout), await(), await(timeout)等方法都是可以被interrupt()方法中断的。

三、synchronized关键字

1、synchronized(object): 同步方法或者代码块,锁是一个对象。

2、synchronized(this): this指的是当前对象。

3、针对静态方法,比如synchronized public static void testMethod(),锁是当前的Class类。

4、如果代码抛出异常,锁自动释放。

时间: 2024-12-25 11:56:04

Java并发编程1——线程状态、synchronized的相关文章

JAVA并发编程5_线程状态

JAVA线程的可能处于一下几种状态,任意的时间点一个线程只能处于一个状态. 1. 新建状态(New):创建后尚未启动的线程处于这种状态. 转移时机:创建一个新线程. 2. 就绪状态(Runnable):调用了start()方法,该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权. 转移时机:调用start()方法. 处于Running状态的线程被CPU选择执行其他线程. 执行Thread.yeild(),不保证. 3. 运行状态(Running):就绪状态的线程获得的了CPU的执

JAVA并发编程3_线程同步之synchronized关键字

在上一篇博客里讲解了JAVA的线程的内存模型,见:JAVA并发编程2_线程安全&内存模型,接着上一篇提到的问题解决多线程共享资源的情况下的线程安全问题. 不安全线程分析 public class Test implements Runnable { private int i = 0; private int getNext() { return i++; } @Override public void run() { // synchronized while (true) { synchro

Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)

Java并发编程系列[未完]: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程:线程间的协作(wait/notify/sleep/yield/join) 一.线程的状态 Java中线程中状态可分为五种:New(新建状态),Runnable(就绪状态),Running(运行状态),Blocked(阻塞状态),Dead(死亡状态). New:新建状态,当线程创建完成时为新

Java并发编程:线程的同步

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

【转】Java并发编程:线程池的使用

Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPool

19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果不释放对临界资源的占用权,那么消费者就无法消费队列中的商品,就不会让队列有空间,那么生产者就会一直无限等待下去.因此,一般情况下,当队列满时,会让生产者交出对

Java并发编程:线程池的使用(转)

Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPool

JAVA并发编程4_线程同步之volatile关键字

上一篇博客JAVA并发编程3_线程同步之synchronized关键字中讲解了JAVA中保证线程同步的关键字synchronized,其实JAVA里面还有个较弱的同步机制volatile.volatile关键字是JAVA中的轻量级的同步机制,用来将变量的更新操作同步到其他线程.从内存可见性的角度来说,写入volatile变量相当于退出同步代码块,读取volatile变量相当于进入同步代码块. 旧的内存模型:保证读写volatile都直接发生在main memory中. 在新的内存模型下(1.5)

Java并发编程:线程的创建

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd