第一章 线程的操作

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为时间间隔无限循环执行此任务

Java 并发编程 基础相关推荐

  1. Java并发编程基础--ThreadLocal

    Java并发编程基础之ThreadLocal ​ ThreadLocal是一个线程变量,但本质上是一个以ThreadLocal对象为键.任意对象为值的存储结构,这个结构依附在线程上,线程可以根据一个T ...

  2. Java并发编程的艺术-Java并发编程基础

    第4章 Java并发编程基础 ​ Java从诞生开始就明智地选择了内置对多线程的支持,这使得Java语言相比同一时期的其他语言具有明显的优势.线程作为操作系统调度的最小单元,多个线程能够同时执行,这将 ...

  3. java 并发编程多线程_多线程(一)java并发编程基础知识

    线程的应用 如何应用多线程 在 Java 中,有多种方式来实现多线程.继承 Thread 类.实现 Runnable 接口.使用 ExecutorService.Callable.Future 实现带 ...

  4. java并发编程入门_探讨一下!Java并发编程基础篇一

    Java并发编程想必大家都不陌生,它是实现高并发/高流量的基础,今天我们就来一起学习这方面的内容. 什么是线程?什么是进程?他们之间有什么联系? 简单来说,进程就是程序的一次执行过程,它是系统进行资源 ...

  5. Java并发编程 基础知识学习总结

    Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容,这部分的内容我也是反复学习了好几遍才能理解.本篇博客梳理一下最近从<Java 并发编程的艺术>和他人的博客学习Java并发 ...

  6. 【Java并发编程的艺术】读书笔记——Java并发编程基础

    学习参考资料:<Java并发编程的艺术> 文章目录 1.线程的几种状态 2.如何安全的终止线程 3.线程间通信(重要) 3.1共享内存 3.2消息传递 1.线程的几种状态 线程在运行的生命 ...

  7. Java并发编程基础-ReentrantLock的机制

    同步锁: 我们知道,锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源,在Lock接口出现之前,Java应用程序只能依靠synchronized关键字来实现同步锁 ...

  8. java并发编程基础—生命周期与线程控制

    一.线程生命周期 线程被创建启动以后,他既不是一启动就进入执行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞(Bloc ...

  9. java并发编程基础系列(五): 创建线程的四种方式

    线程的创建一共有四种方式: 继承于Thread类,重写run()方法: 实现Runable接口,实现里面的run()方法: 使用 FutureTask 实现有返回结果的线程 使用ExecutorSer ...

最新文章

  1. 数据安全引担忧?get它,让你吃一颗“定心丸”
  2. d3.js 简易柱形图,入门demo
  3. Codeforces 1093C (思维+贪心)
  4. 对php专业的认识,对PHP要有个全面的认识
  5. TensorFlow Lite支持设备内置会话建模
  6. 《剑指offer》替换空格
  7. Python __str__() 方法
  8. 动态规划-最长上升子序列(LIS)
  9. Java虚拟机(JVM)概念简介
  10. 解读I2C协议和读写流程
  11. 给创业者们推荐一个好的工具
  12. python正则表达式 身份证_正则表达式实现身份证信息验证
  13. 斗鱼开源基于Go实现的微服务框架 Jupiter
  14. 几款百度竞价点击软件测评来一发
  15. 【系统分析师之路】系统分析师知识地图
  16. 区块链和人工智能是否可以保护森林不再被砍伐?
  17. 用计算机演奏歌曲谱子,我要用计算器弹曲子,求亲们发点计算器简谱
  18. gfsj (logmein)
  19. 尝试Ping百度域名后的思考
  20. JScript 方法

热门文章

  1. linux修改服务器时间_操作系统基础解析:Windows和Linux 到底有何不同?
  2. 梅森旋转产生随机数c语言实现,C++生成随机数的实现代码
  3. java 图片的路径_【JAVA技术】如何展现绝对路径下的图片
  4. php psr 编码规范_PHP编码风格规范
  5. 对于DSH算法损失函数的理解
  6. uboot阶段flash分区_1.12.uboot的烧写和flash分区1
  7. C语言学习及项目开发所遇问题总集(一)---Mr.Zhang
  8. 日历控件如何切换语言 vant_看看甘特图控件VARCHART XGantt的亮点
  9. sas java 虚拟机异常_深入理解JAVA虚拟机之异常诊断
  10. 新服务器配置 显示,新服务器配置纪录