希望代码长期运行下去就编写在一个循环里面
涉及一个以往知识点:能否在run方法声明上抛出InterruptedException异常,以便省略run方法内部对Thread.sleep()语句的try…catch处理?不行,子类不能抛出比父类更多的异常
总结:查看Thread类的run()方法的源代码,可以看到其实这两种方式都是在调用Thread对象的run方法,如果Thread类的run方法没有被覆盖,并且为该Thread对象设置了一个Runnable对象,该run方法会调用Runnable对象的run方法。
问题:如果在Thread子类覆盖的run方法中编写了运行代码,也为Thread子类对象传递了一个Runnable对象,那么,线程运行时的执行代码是子类的run方法的代码?还是Runnable对象的run方法的代码?涉及到的一个以往知识点:匿名内部类对象的构造方法如何调用父类的非默认构造方法。
多线程机制会提高程序的运行效率吗?为什么会有多线程下载呢?
是为了抢夺服务器带宽
new Timer().schedule(new TimerTask(){
public void run() {
System.out.println(Thread.currentThread().getName());
}
},
10000, //过十秒启动定时器
1000); //执行周期
package ThreadDemo;
import java.util.*;
public class TimerDemo {
public static void main(String[] args) {
//5秒之后启动定时器并执行代码
new Timer().schedule(new TimerTask(){
@Override
public void run() {
System.out.println("bombing!");
}
}, 5000);
//while循环按打印当前秒数,每过一秒打印一次。
while(true){
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package ThreadDemo;
import java.util.*;
public class TimerDemo {
//定义一个全局静态变量(不能定义在内部类里)
private static int count = 0;
public static void main(String[] args) {
//自定义一个内部类继承TimerTask
class MyTimerTask extends TimerTask{
@Override
public void run() {
count = (count+1)%2;//让count在0和1之间交替
System.out.println("bombing!");
new Timer().schedule(new MyTimerTask(),2000+2000*count);//多长时间后执行是一个动态值
}
}
new Timer().schedule(new MyTimerTask(),2000);
while(true){
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package ThreadDemo;
import java.util.*;
//自定义一个类继承TimerTask,内部调用另一个自定义的TimerTask对象
class MyTimerTask extends TimerTask{
@Override
public void run() {
System.out.println("bombing!");
new Timer().schedule(new MyTimerTask2(),2000);//多长时间后执行是一个动态值
}
}
//自定义一个类继承TimerTask,内部调用另一个自定义的TimerTask对象
class MyTimerTask2 extends TimerTask{
@Override
public void run() {
System.out.println("bombing!");
new Timer().schedule(new MyTimerTask(),4000);
}
}
public class TimerDemo {
public static void main(String[] args) {
new Timer().schedule(new MyTimerTask(),4000);
while(true){
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package ThreadDemo;
public class ThreadTest {
private static boolean bShouldMain = false;//这里相当于定义了控制该谁执行的一个信号灯
public static void main(String[] args) {
new Thread(
new Runnable(){
public void run() {
for(int i=1;i<=50;i++){
//这里使用类的字节码对象作为锁进行同步,但是当需要对同步进行分组时就不科学了
synchronized(ThreadTest.class){
if(bShouldMain){
try {
ThreadTest.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of "+j+", loop of "+i);
}
bShouldMain = true;
ThreadTest.class.notify();
}
}
}
}
).start();
//main方法本身是一个线程,这里是主线程的运行代码
for(int i=1;i<=50;i++){
synchronized(ThreadTest.class){
if(!bShouldMain){
try {
ThreadTest.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of "+j+", loop of "+i);
}
bShouldMain = false;
ThreadTest.class.notify();
}
}
}
}
问题在于两个线程的代码要参照同一个变量,即bShouldMain,即这两个线程的代码要共享数据,所以,把这两个线程的执行代码搬到同一个类中去(注意循环50次不属于各自的业务执行代码):
package ThreadDemo;
public class ThreadTest {
private static boolean bShouldMain = false;//这里相当于定义了控制该谁执行的一个信号灯
public static void main(String[] args) {
//因为用到了匿名内部类,内部类访问的局部变量需要用final修饰
final Business business = new Business();
new Thread(
new Runnable(){
public void run() {
for(int i=1;i<=50;i++){
//这里使用类的字节码对象作为锁进行同步,但是当需要对同步进行分组时就不科学了
business.sub(i);
}
}
}
).start();
//main方法本身是一个线程,这里是主线程的运行代码
for(int i=1;i<=50;i++){
business.main(i);
}
}
}
class Business {
private boolean bShouldSub = true;//最开始该子线程走
public synchronized void sub(int i){
while(!bShouldSub){//用while而不是if线程醒来还会再次进行判断,防止代码被伪唤醒,代码更健壮。还可以防止生产者消费者问题
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of "+j+", loop of "+i);
}
bShouldSub = false;
this.notify();
}
public synchronized void main(int i){
while(bShouldSub){
try {
this.wait();//这里的锁是this
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of "+j+", loop of "+i);
}
bShouldSub = true;
this.notify();
}
}
线程范围内共享数据的示意图
package cn.itcast.heima;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadScopeShareData {
private static Map threadData = new HashMap();//定义一个Map,为每一个线程存放独立数据
public static void main(String[] args) {
//使用循环创建两个线程
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data = new Random().nextInt();//线程产生一个数据
System.out.println(Thread.currentThread().getName()+" has put data: "+data);
threadData.put(Thread.currentThread(),data);
new A().get();//A模块取出数据
new B().get();//B模块取出数据
}
}).start();
}
}
//模块A
static class A{
public void get(){
int data = threadData.get(Thread.currentThread());//取出当前线程中变量的值
System.out.println("A from "+Thread.currentThread().getName()+" has put data: "+data);
}
}
//模块B
static class B{
public void get(){
int data = threadData.get(Thread.currentThread());
System.out.println("B from "+Thread.currentThread().getName()+" has put data: "+data);
}
}
}
package cn.itcast.heima;
import java.util.Random;
public class ThreadLocalTest {
//定义一个ThreadLocal变量存储线程内共享变量
private static ThreadLocal x = new ThreadLocal();
//定义一个ThreadLocal变量存储线程内的实体对象
private static ThreadLocal myThreadScopeData = new ThreadLocal();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+" has put data: "+data);
x.set(data);//存入数据,并且数据已与当前线程关联
//创建实体对象,并向实体对象中存入数据
MyThreadScopeData myData = new MyThreadScopeData();
myData.setName("name"+data);
myData.setAge(data);
//将实体存入ThreadLocal变量中
myThreadScopeData.set(myData);
new A().get();
new B().get();
}
}).start();
}
}
//模块A
static class A{
public void get(){
int data = x.get();//不用指定线程号就取出当前线程中变量的值
System.out.println("A from "+Thread.currentThread().getName()+" has put data: "+data);
//获取线程内存入的实体对象并获取对象中存储的数据
MyThreadScopeData myData = myThreadScopeData.get();
System.out.println("A from "+Thread.currentThread().getName()+" getMyData: "+myData.getName()+","+myData.getAge());
}
}
//模块B
static class B{
public void get(){
int data = x.get();
System.out.println("B from "+Thread.currentThread().getName()+" has put data: "+data);
}
}
}
//定义一个实体
class MyThreadScopeData{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package cn.itcast.heima;
import java.util.Random;
public class ThreadLocalTest {
//定义一个ThreadLocal变量存储线程内共享变量
private static ThreadLocal x = new ThreadLocal();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+" has put data: "+data);
x.set(data);//存入数据,并且数据已与当前线程关联
/*
//创建实体对象,并向实体对象中存入数据
MyThreadScopeData myData = new MyThreadScopeData();
myData.setName("name"+data);
myData.setAge(data);
//将实体存入ThreadLocal变量中
myThreadScopeData.set(myData);*/
//拿到与本线程相关的实例对象,然后向实体对象中存入数据
MyThreadScopeData.getThreadInstance().setName("name"+data);;
MyThreadScopeData.getThreadInstance().setAge(data);;
new A().get();
new B().get();
}
}).start();
}
}
//模块A
static class A{
public void get(){
int data = x.get();//不用指定线程号就取出当前线程中变量的值
System.out.println("A from "+Thread.currentThread().getName()+" has put data: "+data);
/*//获取线程内存入的实体对象并获取对象中存储的数据
MyThreadScopeData myData = myThreadScopeData.get();
System.out.println("A from "+Thread.currentThread().getName()+" getMyData: "+myData.getName()+","+myData.getAge());
*/
//获取本线程相关的实体对象并获取对象中存储的数据
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("A from "+Thread.currentThread().getName()+" getMyData: "+myData.getName()+","+myData.getAge());
}
}
//模块B
static class B{
public void get(){
int data = x.get();
System.out.println("B from "+Thread.currentThread().getName()+" has put data: "+data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from "+Thread.currentThread().getName()+" getMyData: "+myData.getName()+","+myData.getAge());
}
}
}
//定义一个实体
class MyThreadScopeData{
//将该类设计成类似单例模式
private MyThreadScopeData(){}
private static ThreadLocal map = new ThreadLocal();
public static MyThreadScopeData getThreadInstance(){//这里不需要同步,因为ThreadLocal变量与当前线程相关,各个线程会获取各自的实例
MyThreadScopeData instance = map.get();
if(instance==null){//如果实例没有,就创建实例并保存
instance = new MyThreadScopeData();//保证返回的变量不为null
map.set(instance);//存入的实体与当前线程相关,所以该方法不需要加同步
}
return instance;
}
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class MultiThreadShareData {
private static ShareData1 data1 = new ShareData1();
public static void main(String[] args) {
new Thread(new Runnable(){
public void run() {
while(true){
data1.decrement();
}
}
}).start();
new Thread(new Runnable(){
public void run() {
while(true){
data1.increment();
}
}
}).start();
}
}
//定义共享数据类,谁拥有数据,就提供操作该数据的方法
class ShareData1 implements Runnable{
private int j=0;
public synchronized void increment(){
j++;
}
public synchronized void decrement(){
j--;
}
public void run() {
}
}
public class ThreadTest1
{
private int j;
public static void main(String args[]){
ThreadTest1 tt=new ThreadTest1();
Inc inc=tt.new Inc();
Dec dec=tt.new Dec();
for(int i=0;i<2;i++){
Thread t=new Thread(inc);
t.start();
t=new Thread(dec);
t.start();
}
}
private synchronized void inc(){
j++;
System.out.println(Thread.currentThread().getName()+"-inc:"+j);
}
private synchronized void dec(){
j--;
System.out.println(Thread.currentThread().getName()+"-dec:"+j);
}
class Inc implements Runnable{
public void run(){
for(int i=0;i<100;i++){
inc();
}
}
}
class Dec implements Runnable{
public void run(){
for(int i=0;i<100;i++){
dec();
}
}
}
}
Date
所表示的绝对时间转换成要求的形式很容易。例如,要安排在某个以后的 Date 运行,可以使用:schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)。package cn.itcast.heima;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
//创建一个固定大小的线程池,里面有3个线程
ExecutorService threadPool = Executors.newFixedThreadPool(3);
//创建一个缓存的线程池,池中线程不够,会自动创建新的线程
//ExecutorService threadPool = Executors.newCachedThreadPool();
//创建单一线程池,好处是始终保证池中有一个线程存在,如果线程死了,会再创建一个
//ExecutorService threadPool = Executors.newSingleThreadExecutor();
//通过循环向池中添加10个任务,但是同时只有3个任务被池中的3个线程执行,只有这3个任务都执行结束了才会执行其余任务
for(int i=1;i<=10;i++){
final int task = i;
threadPool.execute(new Runnable(){
public void run() {
//任务循环10遍,线程池中的某一个线程就会执行该任务
for(int j=1;j<=10;j++){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" is looping of "+j+" for task "+task);
}
}
});
}
System.out.println("all of 10 tasks has committed!");
threadPool.shutdown();//关闭线程池(当所有的任务执行完毕,所有的线程都空闲下来时,结束池中的所有线程)
//threadPool.shutdownNow();//关闭线程池(立即结束池中的所有线程,即使还有任务没有执行完毕)
//创建一个调度线程池
Executors.newScheduledThreadPool(3).schedule(
new Runnable(){
public void run() {
System.out.println("bombing!");
}
},
3,//delay
TimeUnit.SECONDS);
}
}
package cn.itcast.heima;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool1 = Executors.newSingleThreadExecutor();
//使用Callable编写任务,Future接受返回结果
Future future = threadPool1.submit(
new Callable(){
public String call() throws Exception {
Thread.sleep(2000);
return "hello";
}
});
System.out.println("等待结果");
try {
System.out.println("拿到结果: "+future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
ExecutorService threadPool2 = Executors.newFixedThreadPool(10);
CompletionService completionService = new ExecutorCompletionService(threadPool2);
//向CompletionService中提交10个任务
for(int i=1;i<=10;i++){
final int sequence = i;//记录任务序号
completionService.submit(
new Callable(){
public Integer call() throws Exception {
Thread.sleep(new Random().nextInt(5000));
return sequence;//返回的是当前任务的序号
}
});
}
//获取结果
for (int i = 0; i < 10; i++) {
try {
System.out.println(completionService.take().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
package cn.itcast.heima;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
public static void main(String[] args) {
new LockTest().init();
}
private void init(){
final Outputer outputer = new Outputer();
new Thread(new Runnable(){
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.output("zhangxiaoxiang");//线程如果不上锁,输出就会被打乱
}
}
}).start();
new Thread(new Runnable(){
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.output("lihuoming");
}
}
}).start();
}
static class Outputer{
Lock lock = new ReentrantLock();//创建锁对象
public void output(String name){
int len = name.length();
lock.lock();//上锁
try{
for(int i=0;i
package cn.itcast.heima;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue3 q3 = new Queue3();
//同时创建3个读取线程,3个写入线程
for(int i=0;i<3;i++)
{
new Thread(){
public void run(){
while(true){
q3.get();//读取数据
}
}
}.start();
new Thread(){
public void run(){
while(true){
q3.put(new Random().nextInt(10000));
}
}
}.start();
}
}
}
class Queue3{
private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
ReadWriteLock rwl = new ReentrantReadWriteLock();//创建读写锁对象
//读的方法
public void get(){
rwl.readLock().lock();//读的时候上读锁
try {
System.out.println(Thread.currentThread().getName() + " be ready to read data!");
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName() + "have read data :" + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.readLock().unlock();
}
}
//写的方法
public void put(Object data){
rwl.writeLock().lock();//写的时候上写锁
try {
System.out.println(Thread.currentThread().getName() + " be ready to write data!");
Thread.sleep((long)(Math.random()*1000));
this.data = data;
System.out.println(Thread.currentThread().getName() + " have write data: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.writeLock().unlock();
}
}
}
User user = session.get(id,User.class);//如果数据对象不存在,返回null
User user = session.load(id,User.class);//如果数据对象不存在,则加载的是一个缓存代理对象
User$Proxy extends User{
private Integer id = id;
User realUser = null;
getName(){
if(realUser==null){
realUser = session.get(id);
if(realUser==null)
throw new Exception();
}
return realUser.getName();
}
}
/*
* 示例用法。下面的代码展示了如何利用重入来执行升级缓存后的锁降级(为简单起见,省略了异常处理):
* 当有许多读的线程访问一个数据实体时,如果有一个线程发现该数据实体为空,该线程就需要将读锁释放,上写锁,写入数据
* 然后在释放写锁前重新上读锁
*/
class CachedData {
Object data;
volatile boolean cacheValid;//判断实体中是否有值
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
// Recheck state because another thread might have acquired
// write lock and changed state before we did.
if (!cacheValid) {
data = ...//加载数据
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
rwl.writeLock().unlock(); // Unlock write, still hold read
}
use(data);
rwl.readLock().unlock();
}
}
package cn.itcast.heima;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheDemo {
//定义一个Map,存储多个对象
private Map cache = new HashMap();
public static void main(String[] args) {}
private ReadWriteLock rwl = new ReentrantReadWriteLock();
//获取对象的方法,当多个线程来读(即获取对象时)不需要互斥,只有写的时候才需要互斥,因此需要使用读写锁
public Object getData(String key){
rwl.readLock().lock();//先上读锁,这样多个线程都可以来读
Object value = null;
try{
value = cache.get(key);
//如果线程读的时候发现数据为空,那么就把读锁释放,禁止数据的读取,然后上写锁
if(value == null){
rwl.readLock().unlock();
rwl.writeLock().lock();
try{
//再次判断数据是否存在,因为当一个线程获取写锁完成了数据填充并释放了写锁,另外一个线程也可能获取了写锁,会重复填充数据。
if(value==null){
value = "aaaa";//实际是去queryDB();即查询数据库
}
}finally{
rwl.writeLock().unlock();//数据填充完,释放写锁
}
rwl.readLock().lock();//恢复为读锁
}
}finally{
rwl.readLock().unlock();
}
return value;
}
}
package cn.itcast.heima;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionCommunication {
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
static class Business {//解决两个java文件中都有该类的问题:这里的完整类名是ConditionCommunicaiton.Business,另一个是Business
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();//获取该锁的condition对象
private boolean bShouldSub = true;
public void sub(int i){
lock.lock();
try{
while(!bShouldSub){//while循环防止虚假唤醒(线程被唤醒但是运行条件并不满足)
try {
condition.await();//调用condition对象特有的await方法,调用wait方法不报错,因为condition也是一个object,但是不是预期的方法。
} catch (Exception e) {
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
condition.signal();//调用condition对象特有的signal方法
}finally{
lock.unlock();
}
}
public void main(int i){
lock.lock();
try{
while(bShouldSub){
try {
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
bShouldSub = true;
condition.signal();
}finally{
lock.unlock();
}
}
}
}
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) //如果缓冲区中存入数据的数量等于缓冲区的长度,即缓冲区满了,那么存入线程就进入等待
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;//将存的指针指向缓冲区第一个坐标
++count;
notEmpty.signal();//只换醒取出线程
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) //缓冲区中没有数据可取了,取出线程就进入等待
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;//将取的指针指向第一个坐标
--count;
notFull.signal();//只换醒存入线程
return x;
} finally {
lock.unlock();
}
}
}
package cn.itcast.heima;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreeConditionCommunication {
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
public void run() {
for(int i=1;i<=50;i++){
business.sub2(i);
}
}
}
).start();
new Thread(
new Runnable() {
public void run() {
for(int i=1;i<=50;i++){
business.sub3(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
static class Business {
Lock lock = new ReentrantLock();
//几个线程轮流执行就定义几个condition
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
private int shouldSub = 1;//条件,该第几个线程运行
public void sub2(int i){
lock.lock();
try{
while(shouldSub != 2){
try {
condition2.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub2 thread sequence of " + j + ",loop of " + i);
}
shouldSub = 3;//该第三个线程运行了
condition3.signal();
}finally{
lock.unlock();
}
}
public void sub3(int i){
lock.lock();
try{
while(shouldSub != 3){
try {
condition3.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for(int j=1;j<=20;j++){
System.out.println("sub3 thread sequence of " + j + ",loop of " + i);
}
shouldSub = 1;
condition1.signal();
}finally{
lock.unlock();
}
}
public void main(int i){
lock.lock();
try{
while(shouldSub != 1){
try {
condition1.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequence of " + j + ",loop of " + i);
}
shouldSub = 2;
condition2.signal();
}finally{
lock.unlock();
}
}
}
}
package cn.itcast.heima;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3);
//循环10遍相当于创建了10个线程
for(int i=0;i<10;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
sp.acquire();//获得一盏信号灯,该线程就可以运行了
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"进入,当前已有" + (3-sp.availablePermits()) + "个并发");//获取了可获得许可数
try {
Thread.sleep((long)(Math.random()*10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"即将离开");
sp.release();//线程离开,就释放灯
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName() +
"已离开,当前已有" + (3-sp.availablePermits()) + "个并发");
}
};
service.execute(runnable);
}
}
}
管理停车位,一个小的电子设备,实时性强就要semaphore。
package cn.itcast.heima;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3);//约定需要3个同时到达的线程
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
Thread.sleep((long)(Math.random()*10000));
//getNumberWaiting返回当前在屏障处等待的参与者数目。
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();//在这里到达集合点。都到达之后才会向下执行
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
package cn.itcast.heima;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountdownLatchTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);//计数器的初始值是1
final CountDownLatch cdAnswer = new CountDownLatch(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
System.out.println("线程" + Thread.currentThread().getName() +
"正准备接受命令");
cdOrder.await();//让当前线程等待该计数器到0
System.out.println("线程" + Thread.currentThread().getName() +
"已接受命令");
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"回应命令处理结果");
cdAnswer.countDown();//在当前线程中让计数器减1
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将发布命令");
cdOrder.countDown();//在主线程中将计数器的计数减1,类似于裁判比赛倒计时
System.out.println("线程" + Thread.currentThread().getName() +
"已发送命令,正在等待结果");
cdAnswer.await();//让主线程等待该计数器为0。当上面的3个线程都运行完计数器就为0了。类似于裁判等待运动员到达公布成绩
System.out.println("线程" + Thread.currentThread().getName() +
"已收到所有响应结果");
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown();
}
}
package cn.itcast.heima;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExchangerTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger exchanger = new Exchanger();
service.execute(new Runnable(){
public void run() {
try {
String data1 = "zxx";
System.out.println("线程" + Thread.currentThread().getName() +
"正在把数据" + data1 +"换出去");
Thread.sleep((long)(Math.random()*10000));//线程休息时间不一样,但是先到下一行代码的会等待另一个
String data2 = (String)exchanger.exchange(data1);//传入己方数据,返回对方数据
System.out.println("线程" + Thread.currentThread().getName() +
"换回的数据为" + data2);
}catch(Exception e){}
}
});
service.execute(new Runnable(){
public void run() {
try {
String data1 = "lhm";
System.out.println("线程" + Thread.currentThread().getName() +
"正在把数据" + data1 +"换出去");
Thread.sleep((long)(Math.random()*10000));
String data2 = (String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() +
"换回的数据为" + data2);
}catch(Exception e){ }
}
});
}
}
package cn.itcast.heima;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueTest {
public static void main(String[] args) {
final BlockingQueue queue = new ArrayBlockingQueue(3);//创建一个可阻塞数组队列,允许放3个数据
for(int i=0;i<2;i++){
new Thread(){
public void run(){
while(true){
try {
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName() + "准备放数据!");
queue.put(1);//向队列中添加数据
System.out.println(Thread.currentThread().getName() + "已经放了数据," +
"队列目前有" + queue.size() + "个数据");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
new Thread(){
public void run(){
while(true){
try {
//将此处的睡眠时间分别改为100和1000,观察运行结果
Thread.sleep(1000);//可以调整取的快慢
System.out.println(Thread.currentThread().getName() + "准备取数据!");
//下面两句不能保证是原子性的,一取就马上打印
queue.take();
System.out.println(Thread.currentThread().getName() + "已经取走数据," +
"队列目前有" + queue.size() + "个数据");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
用两个具有1个空间的队列来实现同步通知的功能(你一下,我一下,轮流执行)。
package cn.itcast.heima;
import java.util.Collections;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class BlockingQueueCommunication {
public static void main(String[] args) {
final Business business = new Business();
new Thread(
new Runnable() {
public void run() {
for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();
for(int i=1;i<=50;i++){
business.main(i);
}
}
static class Business {
//产生两个阻塞队列
BlockingQueue queue1 = new ArrayBlockingQueue(1);//控制子线程
BlockingQueue queue2 = new ArrayBlockingQueue(1);//控制主线程
//构造代码块(或匿名构造方法),对所有对象进行初始化。不能用静态代码块,因为是对成员变量进行初始化
{
Collections.synchronizedMap(null);
try {
System.out.println("xxxxxdfsdsafdsa");
queue2.put(1);//一开始主线程不运行,就通过构造代码块在程序运行之前在队列2中放入数据
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sub(int i){//这里如果加synchronized关键字那么会出现死锁
try {
queue1.put(1);//程序一执行让子线程先运行,就先在队列1中放入元素
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequece of " + j + ",loop of " + i);
}
try {
queue2.take();//子线程运行完毕取走队列2的元素让主线程运行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void main(int i){
try {
queue2.put(1);//由于程序开始执行时队列2是满的所以会阻塞在这里
} catch (InterruptedException e1) {
e1.printStackTrace();
}
for(int j=1;j<=100;j++){
System.out.println("main thread sequece of " + j + ",loop of " + i);
}
try {
queue1.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
* 在进行元素读取的时候不要进行其他操作,会出现死循环。
* 比如hasNext正好读到最后一个元素时,其他线程进来执行remove操作,hasNext内部cursor!=count,始终返回true,成为死循环
*/
count=4;
while(hasNext()){
next(){cursor++}//next方法内部原理
}
//hasNext方法内部原理
hasNext(){
if(cursor==count)
return false;
return true;
}
remove(){
count--;count=3;
}
package cn.itcast.heima;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class CollectionModifyExceptionTest {
public static void main(String[] args) {
Collection users = new CopyOnWriteArrayList();//在写的时候有一分拷贝
users.add(new User("张三",28));
users.add(new User("李四",25));
users.add(new User("王五",31));
Iterator itrUsers = users.iterator();
while(itrUsers.hasNext()){
System.out.println("aaaa");
User user = (User)itrUsers.next();
if("李四".equals(user.getName())){
users.remove(user);
//itrUsers.remove();
} else {
System.out.println(user);
}
}
}
}
package cn.itcast.heima;
public class Test {
public static void main(String[] args){
System.out.println("begin:"+(System.currentTimeMillis()/1000));
/*模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。
修改程序代码,开四个线程让这16个对象在4秒钟打完。
*/
for(int i=0;i<16;i++){ //这行代码不能改动
final String log = ""+(i+1);//这行代码不能改动
{
Test.parseLog(log);
}
}
}
//parseLog方法内部的代码不能改动
public static void parseLog(String log){
System.out.println(log+":"+(System.currentTimeMillis()/1000));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
分析:线程如何得到产生的数据?将数据存放在队列中,然后从队列中取
package cn.itcast.heima;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Test {
public static void main(String[] args){
final BlockingQueue queue = new ArrayBlockingQueue(1);//1个数据也可以,
//final BlockingQueue queue = new ArrayBlockingQueue(16);//可以装16个数据
//创建四个线程
for(int i=0;i<4;i++){
new Thread(new Runnable(){
@Override
public void run() {
while(true){
try {
String log = queue.take();//从阻塞队列中拿数据
parseLog(log);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
System.out.println("begin:"+(System.currentTimeMillis()/1000));
/*模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。
修改程序代码,开四个线程让这16个对象在4秒钟打完。
*/
for(int i=0;i<16;i++){ //这行代码不能改动
final String log = ""+(i+1);//这行代码不能改动
{
try {
queue.put(log);//将数据放入队列中
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//parseLog方法内部的代码不能改动
public static void parseLog(String log){
System.out.println(log+":"+(System.currentTimeMillis()/1000));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
考察了阻塞队列的使用
package queue;
public class Test {
public static void main(String[] args) {
System.out.println("begin:"+(System.currentTimeMillis()/1000));
for(int i=0;i<10;i++){ //这行不能改动
String input = i+""; //这行不能改动
String output = TestDo.doSome(input);
System.out.println(Thread.currentThread().getName()+ ":" + output);
}
}
}
//不能改动此TestDo类
class TestDo {
public static String doSome(String input){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String output = input + ":"+ (System.currentTimeMillis() / 1000);
return output;
}
}
分析:
package queue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
public class Test {
public static void main(String[] args) {
final Semaphore semaphore = new Semaphore(1);
final SynchronousQueue queue = new SynchronousQueue();
for(int i=0;i<10;i++){
new Thread(new Runnable(){
public void run() {
try {
semaphore.acquire();//当前线程获取一个信号灯,保证线程一个一个取,而不是10个线程同时取数据(这里用锁也可以)
String input = queue.take();
String output = TestDo.doSome(input);
System.out.println(Thread.currentThread().getName()+ ":" + output);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
System.out.println("begin:"+(System.currentTimeMillis()/1000));
for(int i=0;i<10;i++){ //这行不能改动
String input = i+""; //这行不能改动
try {
queue.put(input);//将数据放在队列中
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//不能改动此TestDo类
class TestDo {
public static String doSome(String input){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String output = input + ":"+ (System.currentTimeMillis() / 1000);
return output;
}
}
package syn;
//不能改动此Test类
public class Test extends Thread{
private TestDo testDo;
private String key;
private String value;
public Test(String key,String key2,String value){
this.testDo = TestDo.getInstance();
/*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象,
以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*/
this.key = key+key2;
this.value = value;
}
public static void main(String[] args) throws InterruptedException{
Test a = new Test("1","","1");
Test b = new Test("1","","2");
Test c = new Test("3","","3");
Test d = new Test("4","","4");
System.out.println("begin:"+(System.currentTimeMillis()/1000));
a.start();
b.start();
c.start();
d.start();
}
public void run(){
testDo.doSome(key, value);
}
}
class TestDo {
private TestDo() {}
private static TestDo _instance = new TestDo();
public static TestDo getInstance() {
return _instance;
}
public void doSome(Object key, String value) {
// 以大括号内的是需要局部同步的代码,不能改动!
{
try {
Thread.sleep(1000);
System.out.println(key+":"+value + ":"
+ (System.currentTimeMillis() / 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
分析:
package syn;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
//不能改动此Test类
public class Test extends Thread{
private TestDo testDo;
private String key;
private String value;
public Test(String key,String key2,String value){
this.testDo = TestDo.getInstance();
/*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象,
以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*/
this.key = key+key2;
/* a = "1"+"";
b = "1"+"";//这里a和b都是常量相加,编译器会自动优化为同一对象
*/
this.value = value;
}
public static void main(String[] args) throws InterruptedException{
Test a = new Test("1","","1");
Test b = new Test("1","","2");
Test c = new Test("3","","3");
Test d = new Test("4","","4");
System.out.println("begin:"+(System.currentTimeMillis()/1000));
a.start();
b.start();
c.start();
d.start();
}
public void run(){
testDo.doSome(key, value);
}
}
class TestDo {
private TestDo() {}
private static TestDo _instance = new TestDo();
public static TestDo getInstance() {
return _instance;
}
// private ArrayList keys = new ArrayList();//这里不能使用ArrayList集合。因为会发生ConcurrentModificationException的问题,此例中会出现一个线程迭代集合的同时另一个线程在往集合中添加元素。比如此例中a线程进入往集合中添加了一个元素,b线程进入因为元素相同就进行迭代操作,这时c线程也是同时执行的,进入后会执行添加操作。出现该错误必须是这种情况出现,否则程序运行不会报错!!
private CopyOnWriteArrayList keys = new CopyOnWriteArrayList();
public void doSome(Object key, String value) {
Object o = key;
if(!keys.contains(o)){
keys.add(o);//如果集合中没有该元素(实际上判断有无元素与之相等),就存入该对象
}else{
//如果有该元素,就直接遍历集合,找到该元素,并用该元素作为同步的锁
for(Iterator iter=keys.iterator();iter.hasNext();){
try {
Thread.sleep(20);//减慢迭代的速度(等着别的线程进行加入元素操作),增加出现并发修改问题的概率
} catch (InterruptedException e) {
e.printStackTrace();
}
Object oo = iter.next();
if(oo.equals(o)){
o = oo;
break;
}
}
}
synchronized(o)
// 以大括号内的是需要局部同步的代码,不能改动!
{
try {
Thread.sleep(1000);
System.out.println(key+":"+value + ":"
+ (System.currentTimeMillis()/1000));//这里将毫秒数除以1000,所以看到的时间会一样
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}