线程状态
- Runnable
- Blocked
sleep、join、wait、synchronized 四个关键字都会使线程进入Blocked状态 - Running
- Dead
synchronized关键字
- Object类有两个监视器相关的方法wait、notify
- synchronized和wait、notify同时使用,wait、notify必须在synchronized中
- synchronized(obj)同步代码块使用obj对象的监视器实现同步
- 实例方法使用synchronized锁定的是当前实例
- 静态方法使用synchronized锁定的是当前类的所有实例
synchronized关键字实现多线程同步
public class TestSynchronized {
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
List<Thread> listThread = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100; j++) {
test.Increase();
}
}
});
listThread.add(thread);
thread.start();
}
// 主线程等待所有子线程执行完成
for (Thread t : listThread) {
t.join();
}
test.print();
}
}
class Test {
int i = 0;
public synchronized void Increase() {
i++;
}
public void print() {
System.out.println(i);
}
}
synchronized配合wait、notify实现生产者消费者
public class ProducerConsumer {
public static void main(String[] args) {
ProCon proCon = new ProCon();
//生产者
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
proCon.pro(i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
}
}).start();
//消费者1
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
proCon.con();
Thread.sleep(3000);
}
} catch (InterruptedException e) {
}
}
}).start();
//消费者2
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
proCon.con();
Thread.sleep(3000);
}
} catch (InterruptedException e) {
}
}
}).start();
}
}
class ProCon {
List<Integer> listProduct = new ArrayList<Integer>();
public synchronized void pro(int pro) throws InterruptedException {
if (listProduct.size() > 100) {
System.out.println(getPrefix() + "库存已满,请稍候再生产");
wait();
}
listProduct.add(pro);
System.out.println(getPrefix() + "生产了:" + pro);
notifyAll();// 通知消费者获取产品
}
public synchronized void con() throws InterruptedException {
if (listProduct.size() <= 0) {
System.out.println(getPrefix() + "库存不足,请及时补货");
wait();
}
Integer cur = listProduct.get(0);
listProduct.remove(cur);
System.out.println(getPrefix() + "取走:" + cur + " 剩余库存:" + listProduct.toString());
notifyAll();// 通知生产者生产产品
}
private String getPrefix() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ").format(new Date()) + Thread.currentThread().getName() + " ";
}
}
volatile关键字
多线程的内存模型:main memory(主存)、working memory(线程栈),线程处理数据时,先把主存中的数据load到本地栈,操作完成后会save回主存,volatile关键词的作用:每次针对该变量的操作都激发一次load and save。
针对多线程使用的变量如果不是volatile或者final修饰的,很有可能产生不可预知的结果(另一个线程修改了这个值,但是之后在某线程看到的是修改之前的值)。其实道理上讲同一实例的同一属性本身只有一个副本。但是多线程是会缓存值的,本质上,volatile就是不去缓存,直接取值。在线程安全的情况下加volatile会牺牲性能。
多线程实现
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestThread {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 1、继承Thread类,资源和Thread绑定,资源无法共享
new Thread1().start();
new Thread1().start();
// 2、实现Runnable接口,资源和Runnable接口绑定,资源可以共享
Thread2 thread2 = new Thread2();
new Thread(thread2).start();
new Thread(thread2).start();
// 3、实现Callable<>接口
ExecutorService e = Executors.newFixedThreadPool(3);
Future future = e.submit(new Thread3());
// future.isDone(); // return true,false 无阻塞
String str = (String) future.get(); // return 返回值,阻塞直到该线程运行结束
System.out.println("主线程结束");
System.out.println(str);
}
}
// 1、继承Thread类
class Thread1 extends Thread {
int i = 0;
@Override
public void run() {
i++;
System.out.println(i);
}
}
// 2、实现Runnable接口
class Thread2 implements Runnable {
int i = 0;
@Override
public void run() {
i++;
System.out.println(i);
}
}
// 3、实现Callable<>泛型接口
// 可以在任务结束后提供一个返回值,Runnable不行
// call方法可以抛出异常,Runnable的run方法不行
// 可以通过运行Callable得到的Fulture对象监听目标线程调用call方法的结果,得到返回值,(fulture.get(),调用后会阻塞,直到获取到返回值)
class Thread3 implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(3000);
System.out.println("子线程结束");
return "test";
}
}
多线程控制类
- ThreadLocal
保存线程的独立变量。对一个线程类(继承自Thread)
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。常用于用户登录控制,如记录session信息。
实现:每个Thread都持有一个TreadLocalMap类型的变量(该类是一个轻量级的Map,功能与map一样,区别是桶里放的是entry而不是entry的链表。功能还是一个map。)以本身为key,以目标为value。
主要方法是get()和set(T a),set之后在map里维护一个threadLocal -> a,get时将a返回。ThreadLocal是一个特殊的容器。
未完待续。。。