第一章 线程的操作
1.1创建多线程的方式
第一种:继承Thread
第二种:实现Runnable接口
1.2线程的常用方法
currentThread(): 获取当前线程
isAlive():判断当前线程是否处于活动状态
sleep():指定毫秒数让当前线程休眠。
getId():获取当前线程的Id
1.3停止线程
停止线程就是线程在处理任务完成之前,停掉正在进行的操作。Thread.stop()可以停止线程,但是最好不要用它,因为这个方法不安全,而且是过时的方法。
大多数停止一个线程操作使用Thread.interrupt().因为这个方法不会终止正在运行的程序,还需要加入一个判断才行。
Java有三种方法可以终止线程:
Ø 使用退出标志,使得线程正常退出,也就是当run方法完成后终止。
Ø 使用stop方法强行终止,坏处:使得一些清理工作等不到完成,而且会对锁定的对象进行解锁,导致数据得不到同步处理。
Ø 使用interrupt来终止,停止不了的线程:
Code Example:
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
System.out.println("i=" +(i+1));
}
}
}
public class Run {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("maincatch");
e.printStackTrace();
}
}
}
从运行结果,interrupt并没有使得线程终止。那如何停止线层呢?
我们先了解如何判断一个线程是否终止:
this.interrupted():测试当前线程是否已经中断,当前线程是指运行this.
interrupted()方法线程。比如以上代码例子,调用的是thread.interrupt()
但是主线程并未中断,所以主线程是一直运行的。要让主线程终止,
Thread.currentThread.interrupt(). 另外,注意此方法自带清除功能第二次检测线程中断状态,就会返回false.
this.isInterrupted():测试线程是否已经中断,测试的是某一个线程对象是否已经中断,不会清除状态。
异常终止:
如果在运行过程中抛出了异常,那么程序不会继续执行。
我们先考虑一种情况,break:
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
if (this.isInterrupted()){
System.out.println("ThreadState: Interrupted");
break;
}
System.out.println("i=" +(i+1));
}
System.out.println("End!");
}
}
输出结果:
其实for循环后面的代码还需继续执行。
那我们抛出异常呢?
如果for循环和后面的代码都在try catch块里面,那么异常抛出后,后面代码就不会执行,如果for循环后面的代码放到了try catch块后面,那还是会执行的。
线程sleep时候中断线程,会进入catch块
public class MyThread extends Thread {
@Override
public void run() {
super.run();
try {
for (int i = 0; i < 500000; i++) {
Thread.sleep(200000);
System.out.println("i=" +(i+1));
}
System.out.println("End!");
} catch(InterruptedException e) {
System.out.println("InterruptedException");
e.printStackTrace();
}
}
}
结果:
使用return停止线程:
其实原因就是,一旦return,方法后面的代码不会执行。
public class MyThread extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 500000; i++) {
if (this.isInterrupted()){
System.out.println("ThreadState: Interrupted");
return;
}
System.out.println("i=" +(i+1));
}
System.out.println("End!");
}
}
输出结果:
之所以break之后,后面的代码还执行,是因为,break只是跳出for循环,并不影响后面的代码的执行。
1.4暂停线程
暂停线程意味着线程还可以继续恢复运行。使用suspend暂停或者挂起线程,使用resume恢复线程。
1.5yield
放弃当前CPU资源,将他让给其他线程去占用CPU时间,但是放弃的时间不确定,可能放弃了马上又获取了。
1.6线程的优先级
第二章 对象及其变量的并发访问
2.1synchronized 方法与对象
public class Data {
public void print(){
try {
System.out.println("Beginprint: ThreadName----"+Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("End!!");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadA implements Runnable{
private Data data;
public ThreadA(Data data) {
this.data = data;
}
@Override
public void run() {
data.print();
}
}
public class ThreadB implements Runnable{
private Data data;
public ThreadB(Data data) {
this.data = data;
}
@Override
public void run() {
data.print();
}
}
public class Run {
public static void main(String[] args) {
Data data = new Data();
Thread a = new Thread(new ThreadA(data));
a.setName("A");
Thread b = new Thread(new ThreadB(data));
b.setName("B");
a.start();
b.start();
}
}
运行结果:
如果我们在Data的方法上加上Synchronized.是什么效果呢?
方法里面的内容顺序执行,但是线程A不一定先执行,这得看谁先拿到锁。
2.2脏读
赋值时是同步的,取值时没有同步,就有可能出现要读取的值被其他线程修改了。
解决方法:取值也同步。
2.3synchronized 锁重入
Synchronized拥有锁重入的功能,也就是在使用synchronized的时候,当一个线程得到了对象锁以后 ,并没有释放锁,当再次请求对象锁时,是可以再次得到的,比如synchronized方法 或者 块内部在调用本类其他方法或者同步块时,是永远可以得到锁的。
public class Data {
public int d = 0;
public synchronized void service1(){
System.out.println("Service1");
synchronized (this) {
d++;
synchronized (this) {
d=d*2;
}
}
service2();
}
public synchronized void service2(){
System.out.println("Service2");
service3();
}
public synchronized void service3(){
System.out.println("Service3");
System.out.println("value:"+d);
}
}
2.4出现异常时,自动释放锁
当synchronized 方法内部或者块里面抛出异常,那么持有的锁会自动释放。
第三章 线程间的通信
3.1线程间不通信的代码示例
public class DataList {
private List<String> list = newArrayList<String>();
public void add(){
list.add("nicky");
}
public int size(){
return list.size();
}
}
public class ThreadA implements Runnable{
private DataList dataList;
public ThreadA(DataList dataList) {
this.dataList = dataList;
}
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
dataList.add();
System.out.println("Add "+(i+1)+"elements");
Thread.sleep(1000);
}
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
}
public class ThreadB implements Runnable{
private DataList dataList;
public ThreadB(DataList dataList) {
this.dataList = dataList;
}
@Override
public void run() {
try {
while (true) {
if (dataList.size() == 5) {
System.out.println("exit!!");
throw newInterruptedException();
}
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public class Runner {
public static void main(String[] args) {
DataList list = new DataList();
Thread t1 = new Thread(new ThreadA(list), "A");
t1.start();
Thread t2 = new Thread(new ThreadB(list), "B");
t2.start();
}
}
他们实现了通信,但是有一个弊端就是线程B不断的轮询,这样会浪费CPU资源。
3.2等待/通知机制
Ø 方法wait()的作用是当前的线程执行等待,然后就阻塞在这儿,直到有其他时间唤醒它。
Ø Wait只能在同步方法或者同步块中被调用
Ø 执行wait,当前线程释放锁
Ø 如果调用wait没有获得锁,则抛出IllegalMonitorStateException,它是一个RuntimeException的子类。
Ø 方法notify也需要在同步方法或块中使用,即在调用前,也必须获得该对象的锁
Ø 如果没有持有适当的锁,则抛出IllegalMonitorStateException
Ø 如果有多个线程等待,线程规划器随便挑选一个,对其发出notify通知
Ø Notify方法执行后,不会立即释放锁;Wait也不是立马就获得锁,
需要等到notify方法的线程执行完程序也就是退出同步块的时候才释放
Ø 当地一个被唤醒的线程执行完毕,它会释放锁,如果此时没有再次使用notify,即便该对象空闲,其他wait状态的线程由于没有得到通知,还需继续处于阻塞状态。
没有得到锁,调用wait抛出异常例子:
public class Run {
public static void main(String[] args) {
try {
String d = "nicky";
d.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试wait方法执行完后,自动释放锁,第二个线程可以进来,因为已经释放锁了。
public class DataList {
private List<String> list = newArrayList<String>();
public void add(){
list.add("nicky");
}
public int size(){
return list.size();
}
public void service(Object lock){
try {
synchronized (lock) {
System.out.println("beginwait......");
lock.wait();
//Thread.sleep(40000); System.out.println("Endwait......");
}
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
public class ThreadA implements Runnable{
private Object lock;
public ThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
System.out.println("Thread AExecuting");
DataList datList = new DataList();
datList.service(lock);
}
}
public class ThreadB implements Runnable{
private Object lock;
public ThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
System.out.println("Thread BExecuting");
DataList datList = new DataList();
datList.service(lock);
}
}
如果上面的wait()改成Thread.sleep();执行结果:
线程B并没有进来,因为sleep之后,一直阻塞,并没有释放锁。
结论:
同样是等待,但是wait会释放锁,sleep却不会释放锁。
在测试Notify释放锁:
public class DataList {
private List<String> list = newArrayList<String>();
public void add(){
list.add("nicky");
}
public int size(){
return list.size();
}
public void service(Object lock){
try {
synchronized (lock) {
System.out.println("beginwait() ThreadName="+Thread.currentThread().getName());
lock.wait();
System.out.println("End wait()ThreadName="+Thread.currentThread().getName());
}
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
public void synNofify(Object lock){
try {
synchronized (lock) {
System.out.println("beginnotify() ThreadName="+Thread.currentThread().getName()+"time="+
System.currentTimeMillis());
lock.notify();
Thread.sleep(5000);
System.out.println("endnotify() ThreadName="+Thread.currentThread().getName()+"time="+
System.currentTimeMillis());
}
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
public class NotifyThreadA implements Runnable{
private Object lock;
public NotifyThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
DataList dataList = new DataList();
dataList.synNofify(lock);
}
}
public class NotifyThreadB implements Runnable{
private Object lock;
public NotifyThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
DataList dataList = new DataList();
dataList.synNofify(lock);
}
}
public class Runner {
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(new ThreadA(lock), "A");
t1.start();
Thread nt1 = new Thread(new NotifyThreadA(lock),"NotifyThread A");
nt1.start();
Thread nt2 = new Thread(new NotifyThreadB(lock),"NotifyThread B");
nt2.start();
}
}
执行结果:
我们可以分析出:
线程A调用wait方法之后,释放锁,Notify A线程进入调用notify之后,并没有立即释放,而是在同步代码块里的方法执行完毕,才释放锁,然后这个时候,线程A被唤醒,可能线程A继续,也可能是Notify ThreadB进入.
测试线程是wait状态,但此时调用了interrupt方法,则会出现Interrupt异常
public class Runner {
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(new ThreadA(lock), "A");
t1.start();
t1.interrupt();
}
}
实验结论:
Ø Wait方法被调用,会立即释放锁,然后该线程进入线程等待池
Ø Norify方法被调用,则必须同步代码块或者让同步方法执行完毕,才会释放锁
Ø 同步代码块或者同步方法中,遇到异常,也会立即释放所
Ø Sleep方法是阻塞方法,调用之后不会立即释放所
Notify方法只会唤醒一个线程:
NotifyAll唤醒所有的线程:
执行结果:都被唤醒,并且执行
带有时间限制的wait(time)方法,在限定时间,看有没有线程唤醒他,如果没有,到时之后,自动唤醒;但不一定立即执行。
执行结果:
到时之后,自动唤醒
3.3生产者与消费者模式
3.3.1一个生产者 一个消费者操作值
public class ValueObject {
public static String value = "";
}
public class Producer {
private String lock;
public Producer(String lock) {
super();
this.lock = lock;
}
public void setValue(){
try {
synchronized (lock) {
if (!ValueObject.value.equals("")) {
lock.wait();
}
String value = System.currentTimeMillis()+"_"+System.nanoTime();
System.out.println("set valueis: "+value);
ValueObject.value = value;
lock.notify();
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public class Consumer {
private String lock;
public Consumer(String lock) {
super();
this.lock = lock;
}
public void getValue(){
try {
synchronized (lock) {
if (ValueObject.value.equals("")) {
lock.wait();
}
System.out.println("get valueis: " +ValueObject.value);
ValueObject.value = "";
lock.notify();
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
public class ProduceThread implements Runnable{
private Producer producer;
public ProduceThread(Producer producer) {
this.producer = producer;
}
@Override
public void run() {
for(;;){
producer.setValue();
}
}
}
public class ConsumeThread implements Runnable{
private Consumer consumer;
public ConsumeThread(Consumer consumer) {
this.consumer = consumer;
}
@Override
public void run() {
for(;;){
consumer.getValue();
}
}
}
public class Runner {
public static void main(String[] args) {
String lock = new String("");
Producer p = new Producer(lock);
Consumer c = new Consumer(lock);
Thread t1 = new Thread(new ProduceThread(p));
Thread t2 = new Thread(new ConsumeThread(c));
t1.start();
t2.start();
}
}
运行结果:
3.3.2多生产与多消费 操作值假死
假死就是线程进入waiting状态,为什么呢,因为有可能你唤醒的是同类而不是异类,比如生产者有可能唤醒的是生产者,消费者有可能唤醒的是消费者
怎么解决呢,很简单,将notify改为notifyAll,将异类全部唤醒。
3.4通过管道进行线程间通信
Java JDK提供了4个类来使得线程间可以通信:
PipedInputStream PipedOutputStream;
PipedReader PipedWriter
字节流
public class WriteData {
public void write(PipedOutputStream out){
try {
System.out.println("write:");
for (int i = 0; i < 300; i++) {
String outData = ""+(i+1);
out.write(outData.getBytes());
System.out.println(outData);
}
System.out.println();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ReadData {
public void read(PipedInputStream in){
try {
System.out.println("read:");
byte[] bytes = new byte[20];
int len = in.read(bytes);
while(len != -1){
String newData = new String(bytes,0,len);
System.out.println(newData);
len = in.read(bytes);
}
System.out.println();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ThreadWrite extends Thread {
private WriteData write;
private PipedOutputStream out;
public ThreadWrite(WriteData write,PipedOutputStream out) {
super();
this.write = write;
this.out = out;
}
@Override
public void run() {
write.write(out);
}
}
public class ThreadRead extends Thread {
private ReadData read;
private PipedInputStream in;
public ThreadRead(ReadData read, PipedInputStreamin) {
this.read = read;
this.in = in;
}
@Override
public void run() {
read.read(in);
}
}
public class Runner {
public static void main(String[] args) {
WriteData write = new WriteData();
ReadData read = new ReadData();
PipedInputStream in = newPipedInputStream();
PipedOutputStream out = newPipedOutputStream();
try {
out.connect(in);
ThreadRead rt = new ThreadRead(read, in);
rt.start();
Thread.sleep(2000);
ThreadWrite wt = new ThreadWrite(write, out);
wt.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
交替执行:
public class DBTools {
private volatile boolean exec = false;
synchronized void backupA(){
try {
while(exec){
wait();
}
for(int i = 0; i < 5; i++){
System.out.println("**********");
}
exec = true;
notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized void backupB(){
try {
while(!exec){
wait();
}
for(int i = 0; i < 5; i++){
System.out.println("##########");
}
exec = false;
notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class BackupA extends Thread{
private DBTools tools;
public BackupA(DBTools tools) {
this.tools = tools;
}
@Override
public void run() {
tools.backupA();
}
}
public class BackupB extends Thread{
private DBTools tools;
public BackupB(DBTools tools) {
this.tools = tools;
}
@Override
public void run() {
tools.backupB();
}
}
public class Runner {
public static void main(String[] args) {
DBTools tools = new DBTools();
for(int i = 0; i < 20; i++){
new BackupA(tools).start();
new BackupB(tools).start();
}
}
}
运行结果:
3.5join方法的使用
Join方法作用就是等待线程销毁
一定是t1线程执行完毕,这个线程对象销毁才会执行主线程后面的代码。
在Join的时候,线程被中断,会抛出InterruptException异常
带有参数的join方法:如果join方法带有参数,那么到时间之后,如果运行join的线程还没有执行完毕,那么主线程就不必等了。
Sleep(long time) vs Join(long time):
都可以让线程等会儿,但是sleep是不会释放锁的,join默认采用的而是wait机制,所以是会释放锁的,那么其他线程话可以进入同步块或者同步方法继续执行。
第四章 Lock的使用
4.1简单的测试
执行结果:
public class Service2 {
private Lock lock = new ReentrantLock();
public void methodA(){
try {
lock.lock();
System.out.println("Method Abegin Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("Method Aend Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void methodB(){
try {
lock.lock();
System.out.println("Method Bbegin Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("Method Bend Thread Name="+Thread.currentThread().getName()+"time="+System.currentTimeMillis());
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class MyThreadAimplements Runnable {
private Service2 service;
public MyThreadA(Service2 service) {
this.service = service;
}
@Override
public void run() {
service.methodA();
}
}
public class MyThreadB implements Runnable {
private Service2 service;
public MyThreadB(Service2 service) {
this.service = service;
}
@Override
public void run() {
service.methodB();
}
}
public class MainExecute {
public static void main(String[] args) {
Service2 service2 = new Service2();
Thread threadA = new Thread(new MyThreadA(service2));
Thread threadB = new Thread(new MyThreadB(service2));
threadA.start();
threadB.start();
}
}
运行结果:
测试说明:
调用lock.lock()代码,就持有了对象监视器,其他线程只有等待锁被释放时再次争抢,效果和synchronized一样
4.2Condition实现等待、通知的错误用法和正确用法
Condition更加灵活,还可以实现选择性通知
错误用法
没有获取同步监视器:lock.lock()就调用Condition#await方法
这样会抛出异常:IllegalMonitorStateException
正确用法:
public class Service1 {
private Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
public void await(){
try {
lock.lock();
System.out.println("await time= "+ System.currentTimeMillis());
condition.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void singal(){
try {
lock.lock();
System.out.println("singaltime = "+ System.currentTimeMillis());
condition.signal();
} finally{
lock.unlock();
}
}
}
public class MyThreadA implements Runnable {
private Service1 service;
public MyThreadA(Service1 service) {
this.service = service;
}
@Override
public void run() {
service.await();
}
}
public class MainExecute {
public static void main(String[] args) throws InterruptedException {
Service1 service1 = new Service1();
Thread threadA = new Thread(new MyThreadA(service1));
threadA.start();
Thread.sleep(3000);
service1.singal();
}
}
4.3使用多个Condition实现通知部分线程
public class Service1 {
private Lock lock = new ReentrantLock();
public Condition conditionA = lock.newCondition();
public Condition conditionB = lock.newCondition();
public void awaitA(){
try {
lock.lock();
System.out.println("Beginawait A, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());
conditionA.await();
System.out.println("Finishawait A, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());
} catch (InterruptedExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void awaitB(){
try {
lock.lock();
System.out.println("Beginawait B, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());
conditionB.await();
System.out.println("Finishawait B, thread name: "+Thread.currentThread().getName()+"time ="+ System.currentTimeMillis());
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void singalAll_A(){
try {
lock.lock();
System.out.println("singalAll_Athread name: "+Thread.currentThread().getName()+"time = "+ System.currentTimeMillis());
conditionA.signalAll();
} finally{
lock.unlock();
}
}
public void singalAll_B(){
try {
lock.lock();
System.out.println("singalAll_Bthread name: "+Thread.currentThread().getName()+"time = "+ System.currentTimeMillis());
conditionB.signalAll();
} finally{
lock.unlock();
}
}
}
public class MyThreadA implements Runnable {
private Service1 service;
public MyThreadA(Service1 service) {
this.service = service;
}
@Override
public void run() {
service.awaitA();
}
}
public class MyThreadB implements Runnable {
private Service1 service;
public MyThreadB(Service1 service) {
this.service = service;
}
@Override
public void run() {
service.awaitB();
}
}
public class MainExecute {
public static void main(String[] args) throws InterruptedException {
Service1 service1 = new Service1();
Thread threadA = new Thread(new MyThreadA(service1),"A");
Thread threaB = new Thread(new MyThreadB(service1),"B");
threadA.start();
threaB.start();
Thread.sleep(3000);
service1.singalAll_A();
}
}
测试结果:只会唤醒A线程
4.4生产者和消费者
4.4.1一对一
public class Service1 {
private Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set(){
try {
lock.lock();
while (hasValue == true) {
condition.await();
}
System.out.println("##########");
hasValue = true;
condition.signal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get(){
try {
lock.lock();
while (hasValue == false) {
condition.await();
}
System.out.println("**********");
hasValue = false;
condition.signal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class MyThreadA implements Runnable {
private Service1 service;
public MyThreadA(Service1 service) {
this.service = service;
}
@Override
public void run() {
for (int i = 0; i < 5; i++){
service.set();
}
}
}
public class MyThreadB implements Runnable {
private Service1 service;
public MyThreadB(Service1 service) {
this.service = service;
}
@Override
public void run() {
for (int i = 0; i < 5; i++){
service.get();
}
}
}
public class MainExecute {
public static void main(String[] args) throws InterruptedException {
Service1 service1 = new Service1();
Thread threadA = new Thread(new MyThreadA(service1),"A");
Thread threaB = new Thread(new MyThreadB(service1),"B");
threadA.start();
threaB.start();
}
}
输出结果:
4.4.2多对多
先看容易假死的情况:
public class MainExecute {
public static void main(String[] args) throws InterruptedException {
Service1 service1 = new Service1();
Thread[] threadAList = new Thread[10];
Thread[] threadBList = new Thread[10];
Thread threadA = null;
Thread threadB = null;
for (int i = 0; i < 10; i++) {
threadA = new Thread(new MyThreadA(service1),"A"+(i+1));
threadB = new Thread(new MyThreadB(service1),"B"+(i+1));
threadAList[i] = threadA;
threadBList[i] = threadB;
}
for(int i = 0; i < 10; i++){
threadAList[i].start();
threadBList[i].start();
}
}
}
可能程序运行一会儿,还没有运行完,就不运行了,但是线程并没有结束,这就是假死造成的,唤醒的线程不正确,导致可能都在await
解决办法:
Singal 改成singalAll,每一次唤醒都是把对方的唤醒,让这些都唤醒的去抢锁,然后一个线程改变了值,剩余的唤醒线程就等待,直到再次他们被唤醒。
public class Service1 {
private Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
private boolean hasValue = false;
public void set(){
try {
lock.lock();
while (hasValue == true) {
condition.await();
}
System.out.println("##########");
hasValue = true;
condition.signalAll();
} catch (InterruptedExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void get(){
try {
lock.lock();
while (hasValue == false) {
condition.await();
}
System.out.println("**********");
hasValue = false;
condition.signalAll();
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
4.5公平锁与非公平锁
所谓公不公平,其实就是按照是不是先来先获取锁,非公平的是随机的获取锁,而公平的是按照先来先获取锁。
在构造lock的时候,加一个boolean值,如果为true,表示是公平锁。
4.6一些常用方法
GetHoldCount:查询当前线程保持此锁的个数,也就是调用lock方法的次数
GetQueueLength:返回正在等待获取锁的线程估计数
GetWaitQueueLength(Condition condition):返回等待与此锁定相关给定条件Condition线程估计数,比如有5线程,每一个线程都执行了同一个condition对象的await方法,则返回值是5.
HasQueuedThread(Thread thread):查询此线程是否正在等待获取此锁
HasQueuedThreads():查询是否有线程正在等待获取此锁
hasWiaters(Condition condition):查询是否有线程是否正在等待与此锁有关的condition
isFair:判断是不是公平锁
isHeldByCurrentThread:查询当前线程是否保持此锁
isLocked:查询此锁是否由任意线程保持
lockInterruptibly:如果当前线程未被中断,获取此锁,如果已被中断,则抛出异常
tryLock:尝试获取锁,如果获取成功,标记下该线程获取到了锁,然后返回ture,如果没有直接给返回false.
tryLock(long timeout,TimeUnit unit):在给定时间范围内吗,去尝试获取锁,如果获取成功,标记下该线程获取到了锁,然后返回ture,如果没有直接给返回false.如果超时,则不会去尝试获取锁了。
await():让线程进入等待通知状态,在未接受到通知之前,可通过中断结束等待状态,并抛出异常
awaitUninterruptibly: 让线程进入等通知待状态,无法被中断
awaitNanos:若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,则返回0或负数。
awaitUntil: 适用条件与行为与awaitNanos(long nanosTimeout)完全一样,唯一不同点在于它不是等待指定时间,而是等待由参数指定的某一时刻。
4.7ReentrantReadWriteLock读写锁
特点:读读共享;写写互斥;读写互斥;写读互斥
读读共享:
如果读读共享,说明只要是读,应该都可以进去,而不是一个线程独占锁,另外一个读线程需要等到
运行结果:
几乎同一时间进入,第二个线程并没有等待10s
写写互斥:
运行结果是第一个线程执行完了,第二个线程才能获取所进来
同样读写是一样的,如果你读的时候,写的线程进不来;写的时候,也不能读
第五章 定时器Timer
5.1schedule方法测试
指定日期执行某一任务:
5.2方法schedule(TimeTask task,Date firstTime,long period):
指定日期后,按指定的时间间隔无线循环执行某一任务
public class TimerTest {
private static Timer timer = new Timer();
static public class MyTask extendsTimerTask{
@Override
public void run() {
System.out.println("Running!Time is: "+new Date());
}
}
public static void main(String[] args) {
try {
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2016-10-1114:26:00";
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:"+dateRef.toLocaleString()+" 当前时间: "+new Date().toLocaleString());
timer.schedule(task, dateRef, 2000);
} catch(ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
输出结果:
指定时间后,每隔2000ms执行一次任务。
5.3schedule(TimeTask task, long delays)
在当前时间为基础,延迟delys毫秒后执行任务:
5.4schedule(TimeTask task,long delays,long period)
当前时间为基准,延迟delys毫秒后,然后以perid为时间间隔无限循环执行此任务