本文已参与「新人创作礼」活动,一起开启掘金创作之路。
线程安全
线程漏洞最典型的例子就是网上售票。
new Thread(saleThread,"线程一");
new Thread(saleThread,"线程二");
new Thread(saleThread,"线程三");
new Thread(saleThread,"线程四");
上述会发生一张票被多次售出的情况。 归纳 当多线程共享一个共同资源时,会出现如上问题。 原因 线程随机性原理,即线程会被cpu随机切换。 解决方法
-
设置变量 if(bool) 可访问 if(!bool)不可访问
-
synchronized 同步代码块
synchronized(lock){
操作共享资源代码块
}
同步方法
synchronized 返回值类型 方法名([参数1,...]){
//balalala
}
public synchronized void set(String name) {
if (isConsume) {
count++;
this.name = name + count;
System.out.println(Thread.currentThread().getName() + "生产了"+ this.name);
isConsume = false;
}
//
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void get() {
if (!isConsume) {System.out.println(Thread.currentThread().getName() + "消费了" + name);
isConsume = true;
}
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.lock替换synchronized java.util.concurrent.locks.Lock
lock = new ReentrantLock();
condition_producer = lock.newCondition();
condition_consumer = lock.newCondition();
synchronized -> lock.lock();
public void set(String name) {
lock.lock();
try {
//生产了
condition_consumer.signal();
// 消费了才出来生产
condition_producer.await();
} finally {
lock.unlock();// 必须执行!!!!!防止死锁!!
}
}
public void get() {
lock.lock();
try {
"消费了"
condition_producer.notify();
condition_consumer.wait();
} finally {
lock.unlock();
}
}
Lock
- void lock()
获取锁。
- void lockInterruptibly()
如果当前线程未被中断,则获取锁。
- Condition newCondition()
返回绑定到此 Lock 实例的新 Condition 实例。
- boolean tryLock()
仅在调用时锁为空闲状态才获取该锁。
- boolean tryLock(long time, TimeUnit unit)
如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
- void unlock()
释放锁。
wait(), notify(), notify All()
- wait() 是当前cpu放弃同步锁并进入等待(释放cpu,释放锁),直到其他线程进入同步锁,并调用notify()或notify All()唤醒该线程为止
- notify() 唤醒同步锁上等待的第一个调用wait()的线程
- notify All() 唤醒同步锁上调用wait()的所有线程 注意: 上述三种方法必须在同步代码块或同步方法里 必须由锁对象调用 IllegalMonitorStateException 非法的监控异常
sleep()和wait()的区别
描述 | sleep | wait |
---|---|---|
属于哪个类 | Thread | Object |
是否让出cpu | 是 | 是 |
是否释放锁 | 否 | 是 |
时间 | 可以 | 可以 |
使用要求 | 无 | 必须在同步里面,锁对象调用 |
中断InterruptedException | 线程终止 | 线程终止 |
#线程状态 |
- BLOCKED
受阻塞并且正在等待监视器锁的某一线程的线程状态。
public void run() {
synchronized (this) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadBlocked ttw = new ThreadBlocked();
Thread thread1 = new Thread(ttw);
Thread thread2 = new Thread(ttw);
thread1.start();
thread2.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread2.getState());
}
- NEW
至今尚未启动的线程的状态。
public void run() {}
public static void main(String[] args) {
Thread thread = new Thread();
/**休眠一下 给时间切换到线程thread 否则输出主线程main的状态**/
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getState());
}
- RUNNABLE
可运行线程的线程状态。
public void run() {}
public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
System.out.println(thread.getState());
}
- TERMINATED
已终止线程的线程状态。
public void run() {}
public static void main(String[] args) {
ThreadTerminated ttw = new ThreadTerminated();
Thread thread = new Thread(ttw);
thread.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getState());
}
- TIMED_WAITING
具有指定等待时间的某一等待线程的线程状态。
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ThreadTimeWaiting ttw = new ThreadTimeWaiting();
Thread thread = new Thread(ttw);
thread.start();
/**
* 休眠一下 切换到线程thread 否则输出主线程main的状态
*/
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getState());
}
- WAITING
某一等待线程的线程状态。
public void run() {
synchronized (this) {
try {
wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadWaiting ttw = new ThreadWaiting();
Thread thread = new Thread(ttw);
thread.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getState());
}
线程池
管理线程,存放等待线程 Thread创建的线程不在线程池里面。 通过线程池创建的线程默认为后台线程,优先级默认为Normal. 执行方法execute,结束方法shutdown
优点:线程的创建与销毁都要耗费大量的时间,创建多线程也会占据大量的空间。线程池的出现不仅利于管理,还解决了上述问题。