定义任务
线程可以驱动任务,我们通过实现 Runnable 接口来提供,需要实现 Runnable 接口的 run() 方法。
package com.kevindai.concurrency;
public class LiftOff implements Runnable{
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public LiftOff() {
}
public LiftOff(int countDown) {
super();
this.countDown = countDown;
}
public String status() {
return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff") + "),";
}
@Override
public void run() {
while (countDown-- > 0) {
System.out.print(status());
Thread.yield();//线程调度器;建议进行线程调度
}
System.out.println();
}
public static void main(String[] args) {
LiftOff liffOff = new LiftOff();
liffOff.run();
}
}
输出:
我们也可以通过继承 Thread 类覆盖 run() 方法来实现线程类,但继承Thread类有一个缺点就是单继承,而实现Runnable接口则弥补了它的缺点,可以实现多继承。而且实现 Runnable 接口适合多线程共享资源,继承 Thread 类适合各个线程完成自己的任务,因为继承 Thread 类相当于每个线程有一份各自的资源,而实现 Runnable 还可以让多个线程共享一份代码。
Thread类
在代码中一般的使用方式都是将 Runnable 对象转变为任务的过程交给给一个 Thread 构造器。
package com.kevindai.concurrency;
public class BasicThreads {
public static void main(String[] args) {
Thread th = new Thread(new LiftOff());
th.start();
System.out.println("waiting for LiftOff");
}
}
Thread 构造器只需要一个 Runnable 对象。调用 Thread 对象的 start() 方法为该线程执行必须的初始化操作,然后内部调用 Runnable 的 run() 方法。
本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦:
使用 Executor
使用线程池来分配线程
package com.kevindai.concurrency;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CachedThreadPool {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0;i < 5;i++){
exec.execute(new LiftOff());
}
exec.shutdown();
}
}
线程池主要的实现主要包括以下几种:
CacheThreadPool:为每个任务都创建一个线程
FixedThreadPool:一次性预先分配好固定数量的线程
SingleThreadExecutor:线程数唯一,提交多个任务会排队等候
ScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
从任务中产生返回值
如果我们希望任务完成时能够返回一个值,那么可以实现 Callable 接口而不是 Runnable 接口,实现 Callable 接口要求覆盖 Call() 方法。(用此方法使项目的中一个功能的运行速度提高了5倍以上)
package com.kevindai.concurrency;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CachedThreadPool {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService exec = Executors.newCachedThreadPool();
Future<?> f1 = null;
String str1 = "";
for(int i = 0;i < 5;i++){
f1 = exec.submit(new TestReturn("test1", "test2", "", "", "", "", "", ""));
str1 += f1.get();
}
System.out.println(str1);
}
}
package com.kevindai.concurrency;
import java.util.concurrent.Callable;
@SuppressWarnings("rawtypes")
public class TestReturn implements Callable{
private String originalPathList;
private String dhsList;
private String originalIP;
private String originalDirPath;
private String originalType;
private String idsList;
private String isMedia;
private String type;
public TestReturn(String originalPathList, String dhsList,
String originalIP, String originalDirPath, String originalType,
String idsList, String isMedia, String type) {
super();
this.originalPathList = originalPathList;
this.dhsList = dhsList;
this.originalIP = originalIP;
this.originalDirPath = originalDirPath;
this.originalType = originalType;
this.idsList = idsList;
this.isMedia = isMedia;
this.type = type;
}
@Override
public Object call() throws Exception {
return originalPathList + dhsList.toString();
}
}
优先级
线程的优先级将该线程的重要性传递给了调度器。调度器会倾向于让优先级高的线程先
使用方法:Thread.currentThread().setPriority(priority);
自己测试了没测试出什么效果,不写例子了,知道用法就好了
加入线程
一个线程可以在其他线程之上调用 join() 方法,其效果是等待一段时间直到第二个线程结束才继续执行。join() 调用时可以携带超时参数。
package com.kevindai.concurrency.join;
public class Sleeper extends Thread {
private int duration;
public Sleeper(String name,int sleepTime){
super(name);
duration = sleepTime;
start();
}
public void run(){
try {
sleep(duration);
} catch (InterruptedException e) {
System.out.println(getName() + " was interrupted." + "isInterrupted():" + isInterrupted());
return;
}
System.out.println(getName() + " has awakened");
}
}
package com.kevindai.concurrency.join;
public class Joiner extends Thread {
private Sleeper sleeper;
public Joiner(String name,Sleeper sleeper){
super(name);
this.sleeper = sleeper;
start();
}
public void run(){
try {
sleeper.join();
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println(getName() + " join completed");
}
}
package com.kevindai.concurrency.join;
public class Joining {
public static void main(String[] args) {
Sleeper sleepy = new Sleeper("Sleepy", 1500),
grumpy = new Sleeper("Grumpy", 1500);
Joiner dopey = new Joiner("Dopey", sleepy),
doc = new Joiner("Doc", grumpy);
grumpy.interrupt();
}
}
输出:
共享资源
synchronized,是一种同步锁。修饰对象 有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象(一个时间内只能有一个线程得到执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块)
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象(synchronized修饰的方法不能被承继,就算被重写也不是同步的,除非显示的用sychronized修饰)
3. 修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象(共享同一把锁)
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。