线程优先级: 一共5级
线程的状态:
NEW: 初始状态,线程被创建,还未执行start()
RUNNABLE:运行状态,包括运行态和就绪态
BLOCKED:阻塞状态,表示线程阻塞于锁,阻塞在线程进入synchronized代码快的地方
WAITING:等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待其他线程做出一些特定动作(通知或者中断)
TIME_WAITING:超时等待状态,该状态不同于WAITING,它是可以在指定的时间自行返回的
TERMINATED: 终止状态,表示当前线程已经执行完毕。
jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简单察看当前java进程的一些简单情况。
跑一个java线程状态的程序,执行jps,获取到线程pid,然后jstack pid查看线程的状态。
Daemon线程
Daemon线程是支持型线程,主要作为后台调度或支持型工作,当java虚拟机中不存在非daemon线程时,java虚拟机将会推出。谨记,不要用finally代码块清理daemon线程,因为当java虚拟机退出时,是不会执行finallly代码块的
启动和终止线程
线程在init时,需要提供线程所需要的属性,如所属线程组,线程优先级,是否为Daemon,查看线程初始化源码,一个新构造的线程对象是由其parent线程来进行空间分配的,child继承parent的,是否为Daemon,优先级,加载资源的contextClassLoader,及inheritableThreadLocals。初始化后,线程在堆中等待运行。
start()启动线程
中断
中断可以理解为线程的一个标志位属性,许多声明抛出InterrupptedException的方法在抛出异常之前,java虚拟机会先将线程中的中断标志位清除,对于sleep中的线程,调用interrupt()方法,中断标志位会被清除,而runnable状态的线程调用interrupt()方法,中断标志位不会被清除
public class Interrupted {
public static void main(String[] args){
// SleepThread一直不停得尝试睡眠
Thread sleepThread=new Thread(new SleepThread());
sleepThread.setDaemon(true);
Thread busyThread=new Thread(new BusyThread());
busyThread.setDaemon(true);
sleepThread.start();
busyThread.start();
SleepUtils.second(5);
sleepThread.interrupt();
busyThread.interrupt();
System.out.println("SleepThread interrupted is "+ sleepThread.isInterrupted());
System.out.println("BusyThread interrupted is "+busyThread.isInterrupted());
SleepUtils.second(2);
}
static class SleepThread implements Runnable {
public void run() {
while (true) {
SleepUtils.second(10);
}
}
}
static class BusyThread implements Runnable {
public void run() {
while (true) {
}
}
}
public static class SleepUtils {
public static void second(long seconds) {
try {
Thread.sleep(seconds);
} catch (InterruptedException e) {
// do nothing
}
}
}
}
输出结果
SleepThread interrupted is false
BusyThread interrupted is true
过期的suspend(),resume(),和stop()
分别对线程执行暂停,重启,和停止,以suspend为例,它在暂停期间不会释放已经占有的资源(比如锁),而占着锁进入睡眠状态很容易引起死锁。所以这些方法被deprecated了,这些方法可以由wait()和notify()来代替。
安全的终止线程
可以通过interrupt或者利用boolean变量来控制是否需要停止任务
import java.util.concurrent.TimeUnit;
public class Shutdown {
public static void main(String[] args) throws InterruptedException {
Runner one = new Runner();
Thread countThread = new Thread(one, "CountThread");
countThread.start();
TimeUnit.SECONDS.sleep(1);
countThread.interrupt();
Runner two = new Runner();
countThread = new Thread(two, "CountThread");
countThread.start();
TimeUnit.SECONDS.sleep(1);
two.cancel();
}
public static class Runner implements Runnable {
private long i;
private volatile boolean on = true;
public void run() {
while (on && !Thread.currentThread().isInterrupted()) {
i++;
}
System.out.println("Count i=" + i);
}
public void cancel() {
on = false;
}
}
}
输出:
Count i=446723267
Count i=456889859
这种通过标识位或者中断操作的方式,能够使线程在终止时有机会去清理资源,更加安全的终止线程。
线程间通信
javac Synchronized.java,对类文件进行编译,生成Synchronized.class
javap -v Sycnhronzied.class 对字节码文件进行反编译
public class Synchronized {
public static void main(String[] args) {
synchronized (Synchronized.class) {
}
m();
}
public static synchronized void m() {
}
}
//反编译后代码
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: ldc #2 // class Synchronized
2: dup
3: astore_1
4: monitorenter // monitorenter: 监视器进入,获取锁
5: aload_1
6: monitorexit // monitorexit:监视器退出,释放锁
7: goto 15
10: astore_2
11: aload_1
12: monitorexit
13: aload_2
14: athrow
15: invokestatic #3 // Method m:()V
18: return
public static synchronized void m();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=0, locals=0, args_size=0
0: return
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class WaitNotify {
static boolean flag = true;
static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread waitThread = new Thread(new Wait(), "WaitThread");
waitThread.start();
TimeUnit.SECONDS.sleep(1);
Thread notifyThread = new Thread(new Notify(), "NotifyThread");
notifyThread.start();
}
static class Wait implements Runnable {
public void run() {
// 加锁,拥有lock的monitor
synchronized (lock) {
// 当条件不满足时,继续wait,并且释放lock的锁
while (flag) {
try {
System.out.println(
Thread.currentThread() + " flag is true. wait@"
+ new SimpleDateFormat("HH:mm:ss")
.format(new Date()));
lock.wait();
} catch (InterruptedException e) {
// do nothing
}
}
// 条件满足,完成工作
System.out.println(Thread.currentThread()
+ " flag is false. running@"
+ new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
static class Notify implements Runnable {
@Override
public void run() {
// 加锁,拥有lock的monitor
synchronized (lock) {
// 获取lock的锁,然后进行notify,通知时不会释放lock的锁,此时,线程由waiting状态变成blocked状态
// 也就是从等待队列到了同步队列中
// 直到当前线程释放了lock之后,WaitThread才能从wait方法中返回
System.out.println(Thread.currentThread()
+ " hold the lock. notify@"
+ new SimpleDateFormat("HH:mm:ss").format(new Date()));
lock.notify();
flag = false;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
}
}
synchronized (lock) {
System.out.println(Thread.currentThread()
+ " hold the lock again. sleep@"
+ new SimpleDateFormat("HH:mm:ss").format(new Date()));
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
}
}
}
}
}
输出:
Thread[NotifyThread,5,main] hold the lock. notify@16:42:24
Thread[NotifyThread,5,main] hold the lock again. sleep@16:42:26
Thread[WaitThread,5,main] flag is false. running@16:42:28
synchronized(对象){
while(条件不满足){
对象.wait()
}
对应的逻辑处理
}
synchronized(对象){
改变条件
对象.notify()
}
管道输入输出流
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
public class Piped {
public static void main(String[] args) throws IOException {
PipedWriter out = new PipedWriter();
PipedReader in = new PipedReader();
// 将输出流和输入流进行连接,否则在使用时会抛出IOException
out.connect(in);
Thread printThread = new Thread(new Print(in), "PrintThread");
printThread.start();
int receive = 0;
try {
while ((receive = System.in.read()) != -1) {
out.write(receive);
}
} finally {
out.close();
}
}
static class Print implements Runnable {
private PipedReader in;
public Print(PipedReader in) {
this.in = in;
}
public void run() {
int receive = 0;
try {
while ((receive = in.read()) != -1) {
System.out.println((char) receive);
}
} catch (IOException e) {
}
}
}
}
对于Piped类型的流,必须先要进行绑定,也就是connect()
public class Join {
public static void main(String[] args) {
Thread previous = Thread.currentThread();
for (int i = 0; i < 10; i++) {
//每个线程拥有前一个线程的引用,需要等待前一个线程终止,才能从等待中返回
Thread thread=new Thread(new Domino(previous),String.valueOf(i));
thread.start();
previous=thread;
}
System.out.println(Thread.currentThread().getName()+" terminated");
}
static class Domino implements Runnable {
private Thread thread;
public Domino(Thread thread) {
this.thread = thread;
}
public void run() {
try {
thread.join();
} catch (InterruptedException e) {
}
System.out
.println(Thread.currentThread().getName() + " terminated.");
}
}
}
输出:
0 terminated.
1 terminated.
2 terminated.
3 terminated.
4 terminated.
5 terminated.
6 terminated.
7 terminated.
8 terminated.
9 terminated.
// 加锁当前线程对象
public final synchronized void join() throws InterruptedException {
//条件不满足,等待
while(isAlive){
wait(0);
}
//条件满足,方法返回
}
等待超时模式
public synchronized Object get(long millis) throws InterruptedException {
long future=System.currentTimeMillis()+millis;
long remaining=millis;
//当超时大于0并且result返回值不满足要求时
while(result==null&&remaining>0){
wait(remaining);
remaining=future-System.currentTimeMillis();
}
return result;
}
import java.sql.Connection;
import java.util.LinkedList;
public class ConnectionPool {
private LinkedList<Connection> pool = new LinkedList<Connection>();
public ConnectionPool(int initialSize) {
if (initialSize > 0) {
for (int i = 0; i < initialSize; i++) {
pool.addLast(ConnectionDriver.createConnection());
}
}
}
public void releaseConnection(Connection connection) {
if (connection != null) {
synchronized (pool) {
//连接释放后需要进行通知,其他消费者能够感知到连接池中已经归还了一个连接
pool.addLast(connection);
pool.notifyAll();
}
}
}
public Connection fetchConnection(long millis) throws InterruptedException{
synchronized(pool){
//完全超時---我理解就是millis如果设置成负数或者0,获取不到connection的话就一直等待
if(millis<=0){
while(pool.isEmpty()){
pool.wait(0);
}
return pool.removeFirst();
}
else{
long future=System.currentTimeMillis()+millis;
long remaining=millis;
while(pool.isEmpty()&&remaining>0){
pool.wait(remaining);
remaining=future-System.currentTimeMillis();
}
Connection result=null;
result=pool.removeFirst();
return result;
}
}
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.concurrent.TimeUnit;
public class ConnectionDriver {
// InvocationHandler 可以实现java反射
static class ConnectionHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (method.getName().equals("commit")) {
TimeUnit.MILLISECONDS.sleep(100);
}
return null;
}
}
public static final Connection createConnection() {
return (Connection) Proxy.newProxyInstance(
ConnectionDriver.class.getClassLoader(),
new Class<?>[]{Connection.class}, new ConnectionHandler());
}
}
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class ConnectionPoolTest {
static ConnectionPool pool = new ConnectionPool(10);
// 可以修改线程数量
static int threadCount = 10;
// 保证所有ConnectionRunner同时开始
static CountDownLatch start = new CountDownLatch(1);
// main线程会等待所有ConnectionRunner结束后才能继续执行
static CountDownLatch end = new CountDownLatch(threadCount);
public static void main(String[] args) throws InterruptedException {
int count = 20;
AtomicInteger got = new AtomicInteger();
AtomicInteger notGot = new AtomicInteger();
for (int i = 0; i < threadCount; i++) {
Thread thread = new Thread(
new ConnectionRunner(count, got, notGot));
thread.start();
}
start.countDown();
end.await();
System.out.println("total invoke: " + (threadCount * count));
System.out.println("got connection: " + got);
System.out.println("not got connection: " + notGot);
}
static class ConnectionRunner implements Runnable {
int count;
AtomicInteger got;
AtomicInteger notGot;
public ConnectionRunner(int count, AtomicInteger got,
AtomicInteger notGot) {
this.count = count;
this.got = got;
this.notGot = notGot;
}
@Override
public void run() {
try {
start.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
while (count > 0) {
// 从连接池里获取连接,如果1000ms内无法获得,将返回null
// 分别统计连接获取的数量got和未获取到的数量notGot
try {
Connection connection = pool.fetchConnection(1000);
if (connection != null) {
try {
connection.createStatement();
connection.commit();
} catch (SQLException e) {
}
got.decrementAndGet();
} else {
notGot.decrementAndGet();
}
} catch (InterruptedException e) {
} finally {
count--;
}
}
end.countDown();
}
}
}
线程池技术及其实例