标签:结果 缓存 功能 zha 情况下 单元 info 其他 创建
进程:一个正在执行的程序,比如说微信
线程:进程中的一个独立控制单元,线程控制着进程的执行
并行与并发:
①、为了更好的利用cpu的资源,如果只有一个线程,则第二个任务必须等到第一个任务结束后才能进行,如果使用多线程则在主线程执行任务的同时可以执行其他任务,而不需要等待;
②、进程之间不能共享数据,线程可以;
③、系统创建进程需要为该进程重新分配系统资源,创建线程代价比较小;
④、Java语言内置了多线程功能支持,简化了java多线程编程。
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态,释放锁,调用wait(),使该线程处于等待池(wait blocked pool),直到notify()/notifyAll(),线程被唤醒被放到锁定池(lock blocked pool ),使线程回到可运行状态(Runnable)
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。
wait/notify必须存在于synchronized块中。并且,这三个关键字针对的是同一个监视器(某对象的监视器)。这意味着wait之后,其他线程可以进入同步块执行。
当某代码并不持有监视器的使用权时(如图中5的状态,即脱离同步块)去wait或notify,会抛出java.lang.IllegalMonitorStateException。也包括在synchronized块中去调用另一个对象的wait/notify,因为不同对象的监视器不同,同样会抛出此异常。
用法:
synchronized单独使用:
public class Thread1 implements Runnable { Object lock; public void run() { synchronized(lock){ ..do something } } }
public class Thread1 implements Runnable { public synchronized void run() { ..do something } }
/** * 生产者生产出来的产品交给店员 */ public synchronized void produce() { if(this.product >= MAX_PRODUCT) { try { wait(); System.out.println("产品已满,请稍候再生产"); } catch(InterruptedException e) { e.printStackTrace(); } return; } this.product++; System.out.println("生产者生产第" + this.product + "个产品."); notifyAll(); //通知等待区的消费者可以取出产品了 } /** * 消费者从店员取产品 */ public synchronized void consume() { if(this.product <= MIN_PRODUCT) { try { wait(); System.out.println("缺货,稍候再取"); } catch (InterruptedException e) { e.printStackTrace(); } return; } System.out.println("消费者取走了第" + this.product + "个产品."); this.product--; notifyAll(); //通知等待去的生产者可以生产产品了 }
多线程的内存模型:main memory(主存)、working memory(线程栈),在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去(volatile关键词的作用:每次针对该变量的操作都激发一次load and save)。
1、继承Thread类:
步骤:①、定义类继承Thread;
public class ThreadDemo1 { public static void main(String[] args) { //创建两个线程 ThreadDemo td = new ThreadDemo("zhangsan"); ThreadDemo tt = new ThreadDemo("lisi"); //执行多线程特有方法,如果使用td.run();也会执行,但会以单线程方式执行。 td.start(); tt.start(); //主线程 for (int i = 0; i < 5; i++) { System.out.println("main" + ":run" + i); } } } //继承Thread类 class ThreadDemo extends Thread{ //设置线程名称 ThreadDemo(String name){ super(name); } //重写run方法。 public void run(){ for(int i = 0; i < 5; i++){ System.out.println(this.getName() + ":run" + i); //currentThread() 获取当前线程对象(静态)。 getName() 获取线程名称。 } } }
2、实现Runnable接口: 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参方法。
实现步骤: ①、定义类实现Runnable接口
②、覆盖Runnable接口中的run方法
将线程要运行的代码放在该run方法中。
③、通过Thread类建立线程对象。
④、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程执行指定对象的run方法就要先明确run方法所属对象
⑤、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
public class RunnableDemo { public static void main(String[] args) { RunTest rt = new RunTest(); //建立线程对象 Thread t1 = new Thread(rt); Thread t2 = new Thread(rt); //开启线程并调用run方法。 t1.start(); t2.start(); } } //定义类实现Runnable接口 class RunTest implements Runnable{ private int tick = 10; //覆盖Runnable接口中的run方法,并将线程要运行的代码放在该run方法中。 public void run(){ while (true) { if(tick > 0){ System.out.println(Thread.currentThread().getName() + "..." + tick--); } } } }
两种方法对比:
继承Thread:线程代码存放在Thread子类run方法中。
优势:编写简单,可直接用this.getname()获取当前线程,不必使用Thread.currentThread()方法。
劣势:已经继承了Thread类,无法再继承其他类。
实现Runnable:线程代码存放在接口的子类的run方法中。
优势:避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法、无返回值。
五,常用API
currentThread() 获取当前线程,如果在main方法中,则获取的是main,而不是被start()调用的方法
isAlive() 判断当前线程是否处于活跃状态,线程处于正在运行状态,或者准备开始运行的状态,都认为是活跃状态
sleep() 让当前正在执行的
yield() 该方法和sleep方法类似,也是Thread类提供的一个静态方法,可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。
interrupt() 虚拟机会在此线程上标记一个标志(这个中断标志只是一个布尔类型的变量),代表这个线程可能被中断,在后面的中断操作也是根据这个中断标志执行的,如果一个线程被标记了中断标识(调用 interrupt方法),然后调用sleep,wait,jion,io操作等,进入阻塞状态时,会抛出InterruptedException异常,然后清除标识位的中断标记
interrupted():测试当前线程是否中断。 该方法可以清除线程的中断状态 。
isInterrupted():测试这个线程是否被中断。线程的中断状态不受此方法的影响。
六,线程间通信
wait()
notify()
notify()也必须在同步方法或同步块中调用,即在调用前,线程必须获取该对象的级别锁,该方法用于唤醒处于wait状态的线程,此方法执行后,不会释放锁,只有在在notify所在方法块执行完才会释放锁
join()
当B线程执行到了A线程的.join()方法时,B线程就会等待,等A线程都执行完毕,B线程才会执行。
两个队列:
就绪队列
阻塞队列:
lock: 在java.util.concurrent包内。共有三个实现:
ReentrantLock
ReentrantReadWriteLock.ReadLock
ReentrantReadWriteLock.WriteLock
主要目的是和synchronized一样, 两者都是为了解决同步问题,处理资源争端而产生的技术。功能类似但有一些区别。
Lock类的用法也是这样,通过Lock对象lock,用lock.lock
来加锁,用lock.unlock
来释放锁。在两者中间放置需要同步处理的代码。
public class MyConditionService { private Lock lock = new ReentrantLock(); public void testMethod(){ lock.lock(); for (int i = 0 ;i < 5;i++){ System.out.println("ThreadName = " + Thread.currentThread().getName() + (" " + (i + 1))); } lock.unlock(); } }
Condition是Java提供了来实现等待/通知的类,Condition类还提供比wait/notify更丰富的功能,Condition对象是由lock对象所创建的,但是同一个锁可以创建多个Condition的对象,即创建多个对象监视器。这样的好处就是可以指定唤醒线程。notify唤醒的线程是随机唤醒一个。
下面,看一个例子,显示简单的等待/通知
public class ConditionWaitNotifyService { private Lock lock = new ReentrantLock();//创建锁 public Condition condition = lock.newCondition();//创建condition实例 public void await(){ try{ lock.lock();//开启锁 System.out.println("await的时间为 " + System.currentTimeMillis()); condition.await(); System.out.println("await结束的时间" + System.currentTimeMillis()); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock();//释放锁 } } public void signal(){ try{ lock.lock(); System.out.println("sign的时间为" + System.currentTimeMillis()); condition.signal(); }finally { lock.unlock(); } } }
lock.newCondition()
来创建,用condition.await()
来实现让线程等待,是线程进入阻塞。condition.signal()
来实现唤醒线程。唤醒的线程是用同一个conditon对象调用await()
方法而进入阻塞。
标签:结果 缓存 功能 zha 情况下 单元 info 其他 创建
原文地址:https://www.cnblogs.com/zkkkk-/p/10535313.html