一、线程如何创建
创建线程有三种方式:继承Thread类;无返回值的Runnable;有返回值的Callable
示例如下
package com.rcl.platform.demo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CreateThread {
public static class TestThread extends Thread {
@Override
public void run() {
System.out.println("--继承thread--");
}
}
public static class TestRunnable implements Runnable {
@Override
public void run() {
System.out.println("--runnable没有返回值--");
}
}
public static class TestCallable implements Callable {
@Override
public String call() throws Exception {
System.out.println("--callable有返回值--");
return "test-callable";
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Thread thread = new Thread(new TestThread());
thread.start();
thread = new Thread(new TestRunnable());
thread.start();
FutureTask ft = new FutureTask<>(new TestCallable());
thread = new Thread(ft);
thread.start();
System.out.println(ft.get());
}
}
执行结果
--继承thread--
--runnable没有返回值--
--callable有返回值--
test-callable
二、线程相关的方法
join示例
package com.rcl.platform.demo;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class JoinTest {
public static class TestThread extends Thread {
@Override
public void run() {
for(int i=0; i<10; i++){
System.out.println("第" + i + "次执行");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
TestThread thread = new TestThread();
thread.start();
thread.join();
System.out.println("等待thread执行完毕后main线程结束");
}
}
join执行结果
第0次执行
第1次执行
第2次执行
第3次执行
第4次执行
第5次执行
第6次执行
第7次执行
第8次执行
第9次执行
等待thread执行完毕后main线程结束
interrupte示例
package com.rcl.platform.demo;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class JoinTest {
public static class TestThread extends Thread {
@Override
public void run() {
for(int i=0; i<1000000000; i++){
System.out.println("TestThread第" + i + "次执行");
if(Thread.interrupted()){
return;
}
}
}
}
public static class TestThreadSleep extends Thread {
@Override
public void run() {
for(int i=0; i<10; i++){
System.out.println("TestThreadSleep第" + i + "次执行");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(Thread.interrupted()){
return;
}
}
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
TestThread thread = new TestThread();
thread.start();
thread.interrupt();
TestThreadSleep threadSleep = new TestThreadSleep();
threadSleep.start();
threadSleep.interrupt();
}
}
interrupt执行结果
TestThread第0次执行
TestThreadSleep第0次执行
java.lang.InterruptedException: sleep interruptedTestThreadSleep第1次执行
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.rcl.platform.demo.JoinTest$TestThreadSleep.run(JoinTest.java:27)
TestThreadSleep第2次执行
TestThreadSleep第3次执行
TestThreadSleep第4次执行
TestThreadSleep第5次执行
TestThreadSleep第6次执行
TestThreadSleep第7次执行
TestThreadSleep第8次执行
TestThreadSleep第9次执行
三、锁与monitor
java多线程执行的过程中,为了保证共享变量的线程安全,在多线程对共享变量的访问中需要对共享变量进行加锁操作
加锁的形式主要表现为如下三种形式:同步方法、静态同步方法、同步块。
同步方法锁的是调用该方法的对象,为对象锁
静态同步方法是类锁,锁的是该类的class对象
同步块为对象锁,锁的synchronize中的对象
示例
package com.rcl.platform.demo;
public class ThreadState {
public static synchronized void read(){
System.out.println("--这里是类锁--");
}
public synchronized void write(){
System.out.println("--这里是对象锁,锁定的是this对象--");
}
public static void main(String[] args) {
Object lock = new Object();
synchronized (lock) {
System.out.println("--这里是对象锁,锁定的是lock对象--");
}
}
}
四、谈谈volatile
谈到volatile,绕不开的话题还有java内存模型和java编译的重排优化机制
java内存模型
内存操作指令
1)lock,作用于主内存变量,把一个变量标记为线程独占。
2)unlock,与lock正相反。
3)read,作用于主内存变量,它把一个变量从主内存传输到工作内存中。
4)load,作用于工作内存变量,把从read里面获取的变量放入工作内存的变量副本中。
5)use,作用于工作内存变量,把变量的值传递给执行引擎。
6)assign,作用于工作内存变量,把执行引擎的值 复制给工作内存变量。同use相反
7)store,作用于工作内存变量,把工作内存变量传输到主内存中。
8)write,作用于主内存变量,把store获取的值,写入到住内存中的变量。
read & load, store & write成对出现
lock & unlock指令来保证代码的原子性。反映到java代码就是synchronized
volatile关键字的作用:
1)用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新.当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的.但是volatile 不能保证线程是安全的,因为java里面的运算并非原子操作。
2)volatile还有一个特性就是保证指令不重新排序。现在编译器,为了优化代码,都会重新排序指令。如果在多个线程里面,就会有很大的问题。volatile只能保证局部有序
volatile boolean am= false;
public void run() {
context = read();
write(context);
am= true;
say();
cry();
}
只能保证1,2在3之前,4、5在3之后
五、ThreadLocal线程本地变量
使用场景:ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了线程保持对象的方法和避免参数传递的方便的对象访问方式
源码分析
//ThreadLocal 中的 set方法,往线程本地变量设置值,实质上值是存储在一个叫ThreadLocalMap中
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//有此可见,该Map直接存储在Thread本地,与其他线程隔离
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
线程本地变量解决不了共享变量问题,只是在线程中开辟了一块空间存储于该线程相关的变量,其他线程无法访问到该线程的本地变量,但是对于变量在线程初始化以前就已经初始化后在绑定到多个线程的线程本地变量中,无法解决共享问题。
示例
package com.rcl.platform.demo;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class ThreadState {
static Map map = new HashMap<>();
static class Task1 implements Runnable {
ThreadLocal< Map> threadlocal = new ThreadLocal<>();
@Override
public void run() {
try {
threadlocal.set(map);
TimeUnit.SECONDS.sleep(1);
System.out.println("task1:" + map);
map.remove("thread1");
TimeUnit.SECONDS.sleep(1);
System.out.println("task1:" + map);
map = new HashMap<>();
TimeUnit.SECONDS.sleep(1);
System.out.println("task1:" + map);
} catch (InterruptedException e) {
}
}
}
static class Task2 implements Runnable {
ThreadLocal< Map> threadlocal = new ThreadLocal<>();
@Override
public void run() {
try {
threadlocal.set(map);
TimeUnit.SECONDS.sleep(1);
System.out.println("task2:" + map);
TimeUnit.SECONDS.sleep(1);
System.out.println("task2:" + map);
TimeUnit.SECONDS.sleep(1);
System.out.println("task2:" + map);
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) {
map.put("thread1", "thread1");
map.put("thread2", "thread2");
new Thread(new Task1()).start();
new Thread(new Task2()).start();
}
}
运行结果
task2:{thread1=thread1, thread2=thread2}
task1:{thread1=thread1, thread2=thread2}
task2:{thread2=thread2}
task1:{thread2=thread2}
task1:{}
task2:{}
六、线程状态转换
1、java线程有6中状态,分别为NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED详解java.lang.Thread$State枚举类
2、线程初始化为NEW状态,该状态表示还未调用start方法
3、执行线程调用start方法,线程状态转换为RUNNABLE(包括竞争到CPU时间真正意义的执行和没有竞争到CPU时间等待下一个CPU时间的状态)
4、BLOCKED状态为锁竞争,没有竞争到锁为BLOCKED,等待拥有锁的线程释放锁,进入RUNNABLE状态
5、WAITING状态为竞争到锁,执行wait方法,又释放锁,本线程进入WAITING,等待其他线程唤醒notify,notifyall,如果不唤醒,将一直处于WAITING状态
6、TIMED_WAITING为执行sleep join或者有时限的等待
7、线程执行完毕,线程处于TERMINATED状态
线程状态变化
package com.rcl.platform.demo;
import java.util.concurrent.TimeUnit;
public class ThreadState {
public static void main( String[] args ) throws InterruptedException {
System.out.println("-------------NEW-------------");
Thread thread = new Thread();
System.out.println(thread.getState() + ":" + (thread.getState() == Thread.State.NEW));
System.out.println("-------------分割线-------------");
System.out.println("-------------RUNNABLE、TERMINATED-------------");
thread = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getState() + ":" + (Thread.currentThread().getState() == Thread.State.RUNNABLE));
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
System.out.println(thread.getState() + ":" + (thread.getState() == Thread.State.TERMINATED));
System.out.println("-------------分割线-------------");
System.out.println("-------------RUNNABLE、TIMED_WAITING-------------");
thread = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getState() + ":" + (Thread.currentThread().getState() == Thread.State.RUNNABLE));
System.out.println("sleep 进入 TIMED_WAITING");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
System.out.println(thread.getState() );
TimeUnit.SECONDS.sleep(2);
System.out.println("-------------分割线-------------");
System.out.println("-------------RUNNABLE、TIMED_WAITING-------------");
final Thread mainThread = Thread.currentThread();
thread = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getState() + ":" + (Thread.currentThread().getState() == Thread.State.RUNNABLE));
try {
System.out.println("join 进入 TIMED_WAITING");
System.out.println("mainThread: " + mainThread.getState());
TimeUnit.SECONDS.timedJoin(mainThread, 2);//先执行mainthread
System.out.println("mainThread: " + mainThread.getState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
System.out.println("testThread: " + thread.getState() );
System.out.println("-------------分割线-------------");
System.out.println("-------------RUNNABLE、WAITING-------------");
Object lock = new Object();
final Thread mainThread1 = Thread.currentThread();
thread = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
try {
System.out.println("wait 进入 WAITING");
lock.wait();
System.out.println("mainThread1: " + mainThread1.getState() );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
System.out.println("testThread: " + thread.getState() );
synchronized (lock) {
lock.notifyAll();
}
TimeUnit.SECONDS.sleep(1);
System.out.println("-------------分割线-------------");
Thread thread1 = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
}
}
});
thread2.start();
TimeUnit.SECONDS.sleep(1);
System.out.println("thread2: " + thread2.getState() );
}
}
执行结果
-------------NEW-------------
NEW:true
-------------分割线-------------
-------------RUNNABLE、TERMINATED-------------
RUNNABLE:true
TERMINATED:true
-------------分割线-------------
-------------RUNNABLE、TIMED_WAITING-------------
RUNNABLE:true
sleep 进入 TIMED_WAITING
TIMED_WAITING
-------------分割线-------------
-------------RUNNABLE、TIMED_WAITING-------------
RUNNABLE:true
join 进入 TIMED_WAITING
mainThread: TIMED_WAITING
testThread: TIMED_WAITING
-------------分割线-------------
-------------RUNNABLE、WAITING-------------
wait 进入 WAITING
mainThread: TIMED_WAITING
testThread: WAITING
mainThread1: TIMED_WAITING
-------------分割线-------------
thread2: BLOCKED
关于多线程,jdk提供了java.util.concurrent包的多线程解决方案,里面包含原子变量,线程安全的Map,Queue等的实现已经线程管理的线程池的实现,正在整理中,敬请期待