java学习笔记#9-多线程
2018-08-11 本文已影响0人
edwin1993
多线程概念
-
进程:
进程是程序(任务)执行的过程
进程持有资源和线程 -
线程
线程是系统中的最小执行单元
一个进程有多个线程
线程共享进程资源 -
线程的交互:互斥&同步
多线程示例
Java对线程的支持体现在Thread类和Runnable接口
通过继承Thread类实现多线程,但是这种方式有一定的局限性。因为在java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类,比如学生类Student继承了person类,就无法再继承Thread类创建的线程。
为了克服这种弊端,Thread类提供了另外一种构造方法Thread(Runnable target),其中Runnable是一个接口,它只有一个run()方法。
package Base.Multprocess;
/**
* Created by Edwin_1993 on 2018/8/10.
*/
public class ThreadExample extends Thread {
public void run(){
System.out.println(getName() + " threadExample");
int count = 0;
boolean keepRunning = true;
while(keepRunning){
System.out.println((getName()+ " num:" + ++count));
if (count == 100){
keepRunning = false;
}
if (count%10 == 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(getName()+ " end");
}
public static void main(String args[]){
Thread thread = new ThreadExample();
thread.setName("ThreadExample");
thread.start();
Thread runnableThread = new Thread(new RunnableExample(),"Ms Runnable");
runnableThread.start();
}
}
class RunnableExample implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " RunnableExample");
int count = 0;
boolean keepRunning = true;
while (keepRunning) {
System.out.println((Thread.currentThread().getName() + " num:" + ++count));
if (count == 100) {
keepRunning = false;
}
if (count % 10 == 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
多线程的停止方式
-
stop()方法
这是一个错误的方法,会使得线程戛然而止,不知道完成了哪些以及如何清理。 -
interrupt方法
方法初衷并不是停止线程
下方代码无法正确结束线程。
package Base.Multprocess;
/**
* Created by Edwin_1993 on 2018/8/11.
*/
public class WrongWayStopThread extends Thread {
public static void main(String args[]){
WrongWayStopThread wrongWayStopThread = new WrongWayStopThread();
System.out.println("Thread starting ...");
wrongWayStopThread.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread interrupting ...");
wrongWayStopThread.interrupt();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread ending ...");
}
public void run(){
while (true){
// while (!this.isInterrupted()){
System.out.println("Thread is running ...");
long time = System.currentTimeMillis();
while((System.currentTimeMillis() - time) < 1000){
}
}
}
}
上述run方法改写后相当于使用了退出标志。
public void run(){
// while (true){
while (!this.isInterrupted()){
System.out.println("Thread is running ...");
long time = System.currentTimeMillis();
while((System.currentTimeMillis() - time) < 1000){
}
}
}
使用sleep()方法,线程进入了阻塞状态,此时再调用interrupte方法会使得interrupt状态被清除,使得this.isInterrupted()无效,且使得sleep方法被中断:InterruptedException 。
public void run(){
// while (true){
while (!this.isInterrupted()){
System.out.println("Thread is running ...");
long time = System.currentTimeMillis();
while((System.currentTimeMillis() - time) < 1000){
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 使用退出标志:
如下方代码中的keepRunning标志
package Base.Multprocess;
/**
* Created by Edwin_1993 on 2018/8/11.
*/
public class ArmyRunnable implements Runnable{
// volatile 保证了线程可以正确读取其它线程写入的值
// 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
//
// 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
//
// 2)禁止进行指令重排序
volatile boolean keepRunning = true;
@Override
public void run() {
while (keepRunning){
for(int i = 0;i <5;i++){
System.out.println(Thread.currentThread().getName() + "attack["+i+"]");
// t
Thread.yield();
}
}
System.out.println(Thread.currentThread().getName() + "end attack");
}
}
线程交互
-
争用条件:
当多个线程同时访问同一数据的时候,每个线程都在尝试操作该数据,从而导致数据被破环,这种情况叫做争用条件。 -
互斥:
互斥的实现:synchronized(intrinsic lock)
synchronized块中的代码,通过获取lockObj锁来执行。
private final Object lockObj = new Object();
public void transfer(int from ,int to, double amount){
// 通过synchronized进行互斥
synchronized (lockObj){
// if (energyBoxes[from] < amount){
// System.out.println("not enought energy");
// return;
// }
// 满足while条件时,任务被阻挡,不去竞争CPU资源。
while (energyBoxes[from] < amount){
try {
lockObj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(Thread.currentThread().getName());
energyBoxes[from] -= amount;
System.out.printf("从 %d 转移 %10.2f 单位能量到 %d",from,amount,to);
energyBoxes[to] += amount;
System.out.printf("能量总合: %10.2f", getTotalEnergy());
}
// 非互斥模式
// if (energyBoxes[from] < amount){
// System.out.println("not enought energy");
// return;
// }
// System.out.print(Thread.currentThread().getName());
// energyBoxes[from] -= amount;
// System.out.printf("从 %d 转移 %10.2f 单位能量到 %d",from,amount,to);
// energyBoxes[to] += amount;
// System.out.printf("能量总合: %10.2f", getTotalEnergy());
// 唤醒所有在lockObj上等待的线程。
lockObj.notifyAll();
}
- 同步
同步的实现:wait()/notify()/notifyAll()
这些方法都是object类的方法。
上述代码中
当运行条件不满足的时候,通过lockobj.wait()来将线程放入Wait set
当某一条线程顺利执行完成时,通过lockobj.notifyAll()来唤醒所有的等待线程。