线程的创建方式
public Create01(String name) {
super(name);
}
@Override
public void run() {
while (!interrupted()) {
System.out.println(this.getName() + "线程执行了");
}
}
public static void main(String[] args) {
Create01 create01 = new Create01("first"); //Thread-0线程执行了
Create01 create02 = new Create01("second"); //Thread-1线程执行了
create01.start();
create02.start();
}
/**
* 作为线程任务存在
*/
public class Create02 implements Runnable {
@Override
public void run() {
while (true){
System.out.println("thread running");
}
}
public static void main(String[] args) {
Thread thread = new Thread(new Create02());
thread.run();
}
}
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
System.out.println("thread run");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runnable run");
}
}) {
public void run() {
System.out.println("runnable2 run");
}
}.start();
}
thread run
runnable2 run
public class Create04 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("计算中");
Thread.sleep(2000);
return 3;
}
public static void main(String[] args) throws Exception {
Create04 create04 = new Create04();
FutureTask<Integer> task = new FutureTask<>(create04);
new Thread(task).start();
System.out.println("我先干别的");
Integer integer = task.get();
System.out.println(integer);
}
}
计算中
我先干别的
3
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("hahah");
}
},0,1000);
}
hahah
hahah
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
threadPool.shutdown();
}
@Service
public class Create07 {
@Async
public void a() throws InterruptedException {
while (true){
System.out.println("a");
Thread.sleep(2000);
}
}
@Async
public void b() throws InterruptedException {
while (true){
System.out.println("b");
Thread.sleep(2000);
}
}
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
Create07 bean = ac.getBean(Create07.class);
bean.a();
bean.b();
}
}
@Component
@ComponentScan("com.cy.create")
@EnableAsync
public class Config {
}
b
a
b
a
public int add(List<Integer> list){
list.parallelStream().forEachOrdered(System.out::println);
return 0;
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(10, 20, 30);
int res = new Create08().add(list);
System.out.println("计算结果:"+res);
}
10
20
30
计算结果:0
线程的状态
线程活跃性问题
死锁
饥饿
活锁
饥饿与公平:
高优先级吞噬所有低优先级的CPU时间片
线程被永久堵塞在一个等待进入同步块的状态
等待线程不被唤醒
如何避免:
合理设置优先级
使用锁来代替synchronized
优先级
public class YouXianJi implements Runnable{
public static void main(String[] args) {
Thread thread1 = new Thread(new YouXianJi());
Thread thread2 = new Thread(new YouXianJi());
thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
thread1.start();
thread2.start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getId());
}
}
Synchronized加锁防止多线程安全问题
public class Question_Safe {
private int value = 0;
public synchronized int add() {
return value++;
}
public static void main(String[] args) {
Question_Safe question_safe = new Question_Safe();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + question_safe.add());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + question_safe.add());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + question_safe.add());
}
}
}).start();
}
}
总结:线程安全性问题:
多线程环境
多线程共享资源
对资源进行非原子性操作
Synchronized原理与使用(自行释放锁):
synchronized字节码指令:
monitorenter:进入
MyMethod();
monitorexit:退出
任何对象都可以作为锁 那么锁信息又存在于对象的什么地方呢?
存储在对象头中
对象头中有什么信息?
Mark Word
CLass Metadata Address
Array Length
锁的分类
偏向锁:
每次获取锁和释放锁都会浪费资源
很多情况下 竞争锁不是由多个线程 而是由一个线程在使用
Mark Word :
线程id
对象的分代年龄信息
是否是偏向锁
锁标志位
轻量级锁:
自旋
多个线程可以同时
重量级锁
单例模式与线程安全性问题
锁重入
在已经获得锁的同步方法或同步代码块内部可以调用锁定对象的其他同步方法, 不需要重新获取锁.
public class ChongRu_Lock {
public synchronized void a() {
System.out.println("a");
b();
}
public synchronized void b() {
System.out.println("b");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
new ChongRu_Lock().a();
}
}).start();
}
}
自旋锁
是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
public class ZiXuan_Lock {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始执行");
try {
Thread.sleep(new Random().nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "线程执行完毕");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始执行");
try {
Thread.sleep(new Random().nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "线程执行完毕");
}
}).start();
int i = Thread.activeCount();
while (i != 1) {
//自旋
}
System.out.println("所有线程执行完毕");
}
}
死锁
public class Die_Lock {
private Object obj1 = new Object();
private Object obj2 = new Object();
public void a () {
synchronized (obj1) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj2) {
System.out.println("a");
}
}
}
public void b () {
synchronized (obj2) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj1) {
System.out.println("b");
}
}
}
public static void main(String[] args) {
Die_Lock d = new Die_Lock();
new Thread(new Runnable() {
@Override
public void run() {
d.a();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
d.b();
}
}).start();
}
}
Volatile
轻量级锁,被Volatile修饰的变量 线程之间是可见的
可见:一个线程修改了这个变量的值 在另外一个线程中可以读到修改后的值
Synchronized除了线程之间互斥以外 还有一个大作用 就是保证可见性
/**
* 保证可见性的前提
* 多个线程拿到的是同一把锁,否则是保证不了的。
*/
public class Volatile {
public volatile int a = 1;
public synchronized int getA() {
return a++;
}
public synchronized void setA(int a) {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.a = a;
}
public static void main(String[] args) {
Volatile demo = new Volatile();
demo.a = 10;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(demo.a);
}
}).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终的结果为:" + demo.getA());
}
}
public volatile boolean run = false;
public static void main(String[] args) {
Volatile2 d = new Volatile2();
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1;i<=10;i++) {
System.err.println("执行了第 " + i + " 次");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
d.run = true;
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(!d.run) {
// 不执行
}
System.err.println("线程2执行了...");
}
}).start();
Volatile JVM指令分析
Lock:
在多处理器的系统上:
将当前处理器缓存行的内容写回到系统内存
写个写回到内存的操作会使在其他CPU缓存了改内存地址的数据失败
硬盘-内存-CPU缓存(最小单位:缓存行)
JDK通过的原子类的原理的使用(JDK1.5提出)
java.util.concurrent.atomic
public class Sequence {
private AtomicInteger value = new AtomicInteger(0);
private int [] s = {2,1,4,6};
AtomicIntegerArray a = new AtomicIntegerArray(s);
AtomicReference<User> user = new AtomicReference<>();
AtomicIntegerFieldUpdater<User> old = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
/**
* @return
*/
public int getNext() {
User user = new User();
System.out.println(old.getAndIncrement(user));
System.out.println(old.getAndIncrement(user));
System.out.println(old.getAndIncrement(user));
a.getAndIncrement(2);
a.getAndAdd(2, 10);
return value.getAndIncrement();
}
public static void main(String[] args) {
Sequence s = new Sequence();
new Thread(new Runnable() {
@Override
public void run() {
// while(true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// }
}
}).start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// while(true) {
// System.out.println(Thread.currentThread().getName() + " " + s.getNext());
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
// }).start();
//
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// while(true) {
// System.out.println(Thread.currentThread().getName() + " " + s.getNext());
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
// }).start();
}
}
Lock接口的认识和使用
相比synchornized:
Lock需要获取和释放锁 繁琐让代码灵活
Synchronized不需要显示释放和获取锁 简单
使用Lock方便实现公平性
非阻塞的获取锁
能被中断的获取锁
超时获取锁
public class LockTest {
private int value;
Lock lock = new ReentrantLock();
Lock l1 = new ReentrantLock();
public int getNext() {
lock.lock();
int a = value++;
lock.unlock();
return a;
}
public static void main(String[] args) {
Sequence s = new Sequence();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " " + s.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
AQS(AbstractQueuedSynchronizer)
通过AQS实现自己的锁(可重入)
public class MyAQSLock implements Lock {
private Helper helper = new Helper();
private class Helper extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int arg) {
//第一个线程进来 可以拿到锁 返回true
//第二个线程进来 拿不到锁 返回false
//如何判断是第几个线程进来
int state = getState();
Thread thread = Thread.currentThread();
if (state == 0) {
if (compareAndSetState(0, arg)) {
setExclusiveOwnerThread(thread);
return true;
}
} else if (getExclusiveOwnerThread() == thread) {
setState(state + 1);
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
//锁的获取和释放肯定是一一对应的,那么调用此方法的线程一定是当前的线程
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new RuntimeException();
}
int state = getState() - arg;
boolean flag = false;
if (getState() == 0) {
setExclusiveOwnerThread(null);
flag = true;
}
setState(state);
return flag;
}
public Condition newConditoion() {
return new ConditionObject();
}
}
@Override
public void lock() {
helper.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
helper.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return helper.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return helper.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
helper.release(1);
}
@Override
public Condition newCondition() {
return helper.newConditoion();
}
}
public class MyAQSLockTest {
private int value;
private MyAQSLock lock = new MyAQSLock();
public int next() {
lock.lock();
try {
Thread.sleep(300);
return value++;
} catch (InterruptedException e) {
throw new RuntimeException();
} finally {
lock.unlock();
}
}
public void a() {
lock.lock();
System.out.println("a");
b();
lock.unlock();
}
public void b() {
lock.lock();
System.out.println("b");
lock.unlock();
}
public static void main(String[] args) {
MyAQSLockTest m = new MyAQSLockTest();
new Thread(() -> {
m.a();
}).start();
}
}
公平锁
针对锁的获取而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序
读写锁
排他锁与共享锁
public class ReadWriteLock {
private Map<String, Object> map = new HashMap<>();
private java.util.concurrent.locks.ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();
public Object get(String key) {
readLock.lock();
System.out.println("读:" + Thread.currentThread().getName());
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return map.get(key);
} finally {
readLock.unlock();
System.out.println("读完了:" + Thread.currentThread().getName());
}
}
public Object put(String key, Object object) {
writeLock.lock();
System.out.println("写:" + Thread.currentThread().getName());
try {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return map.put(key, object);
} finally {
writeLock.unlock();
System.out.println("写完了:" + Thread.currentThread().getName());
}
}
}
public class ReadWriteLockTest {
public static void main(String[] args) {
ReadWriteLock lock = new ReadWriteLock();
lock.put("key1", "value1");
new Thread((() -> {
lock.get("key1");
})).start();
new Thread((() -> {
lock.get("key1");
})).start();
// new Thread((() -> {
// lock.put("key1","value3");
// })).start();
// new Thread((() -> {
// lock.put("key2","value3");
// })).start();
// new Thread((() -> {
// lock.put("key3","value3");
// })).start();
}
}
读写锁:读锁与读锁之间不排斥 读锁与写锁之间排斥 写锁和写锁之间排斥
读写锁需要保存的状态:
写锁重入的次数
读锁的个数
每个读锁重入的次数
1111 1111 1111 1111(读锁重入个数) - 1111 1111 1111 1111(写锁重入个数) (int:代表重入的次数)
锁降级 写锁降级为读锁
在写锁的没有释放的时候 获取到读锁 再释放到写锁
private boolean isUpdate;
public void readWrite() {
readLock.lock();
if (isUpdate) {
readLock.unlock();
writeLock.lock();
map.put("xxx", "xxx");
readLock.lock();
writeLock.unlock();
}
Object xxx = map.get("xxx");
System.out.println(xxx);
readLock.unlock();
}
锁升级 读锁升级为写锁
在读锁还没有释放的时候 获取到写锁 再释放读锁
线程安全性问题总结
出现线程安全性问题的条件
在多线程的环境下
必须有共享资源
对共享资源进行非原子性操作
解决线程安全性问题的途径
Synchronized(偏向锁 轻量级锁 重量级锁)
Volatile(关键词)
JDK提供的原子类( java.util.concurrent.atomic.*)
Lock接口
认识的锁
偏向锁
轻量级锁
重量级锁
重入锁
自旋锁
共享锁
独占锁
排他锁
读写锁
公平锁
非公平锁
死锁
活锁
线程间通信
wait notify
消费者生产者模型
Condition
Join(加塞)
public class TJoin {
public void a(Thread joinThread) {
System.out.println("a start");
joinThread.start();
try {
joinThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("a finish");
}
public void b() {
System.out.println("加塞线程 start");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("加塞线程 finish");
}
public static void main(String[] args) {
TJoin tJoin = new TJoin();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
tJoin.b();
}
});
new Thread(() -> {
tJoin.a(thread);
}).start();
}
}
ThreadLocal
public class TThreadLocal {
private ThreadLocal<Integer> count = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
public int getNext() {
Integer value = count.get();
value++;
count.set(value);
return value;
}
public static void main(String[] args) {
TThreadLocal t = new TThreadLocal();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + t.getNext());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + t.getNext());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + t.getNext());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
并发工具类:CountDownLatch(汇总线程)