线程的方式
-
Thread和Runnable
相对比较简单就不多做介绍,无非就是Thread是一个类,Runnable是一个接口。 -
ThreadFactory线程工厂
用来创建线程的线程工厂,主要就是newThread方法
static void threadFactory() {
ThreadFactory factory = new ThreadFactory() {
AtomicInteger count = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Thread-" + count.incrementAndGet());
}
};
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " started!");
}
};
Thread thread = factory.newThread(runnable);
thread.start();
Thread thread1 = factory.newThread(runnable);
thread1.start();
}
- Executor和线程池
这篇文章详情介绍了Executor
Android线程池实现原理 - Callable和Future
这个最大的特点就是带返回值,Callable接口代表一段可以调用并返回结果的代码;Future接口表示异步任务,是还没有完成的任务给出的未来结果。所以说Callable用于产生结果,Future用于获取结果。
Callable和Future
static void callable() {
Callable<String> callable = new Callable<String>() {
@Override
public String call() {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Done!";
}
};
ExecutorService executor = Executors.newCachedThreadPool();
Future<String> future = executor.submit(callable);
try {
String result = future.get();
System.out.println("result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
线程同步和安全
synchronized关键字实现同步
- synchronized方法
public synchronized void showA(){
System.out.println("showA..");
}
- synchronized代码块
public void showC(){
String s="1";
synchronized (s) {
System.out.println("showC..");
}
synchronized方法和synchronized代码块区别
两者的区别:Moinitor对象的不同;synchronized代码块可以同步的范围更小更灵活。同步方法的moinitor是类的对象,而synchronized代码块的moinitor就可以也自己来定义,更加方便。synchronized本质
保证方法内部或代码块内部资源(数据)的互斥访问。即同⼀时间、由同⼀个Monitor 监视的代码,最多只能有⼀个线程在访问
保证线程之间对监视资源的数据同步。即,任何线程在获取到 Monitor 后的第⼀时间,会先将共享内存中的数据复制到自己的缓存中;任何线程在释放 Monitor 的第⼀时间,会先将缓存中的数据复制到共享内存中。
volatile关键字 实现字段的原子性和同步性
-
volatile
保证加了volatile关键字的字段的操作具有原⼦性和同步性,其中原⼦性相当于实现了针对单⼀字段的线程间互斥访问。因此 volatile 可以看做是简化版的 synchronized。
volatile 只对基本类型 (byte、 char、 short、 int、 long、 float、 double、 boolean) 的赋值操作和对象的引用赋值操作有效。volatile int a = 1; a++;这种情况不能保证原子性,因为a++有两步操作。 -
java.util.concurrent.atomic 包:
下面有 AtomicInteger AtomicBoolean 等类,作用和 volatile 基本⼀致,使用如下
ThreadFactory factory = new ThreadFactory() {
AtomicInteger count = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Thread-" + count.incrementAndGet());//count++
}
};
- Lock / ReentrantReadWriteLock锁
- Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性
- ReetrantReadWriteLock读写锁的效率明显高于synchronized关键字
- ReetrantReadWriteLock读写锁的实现中,读锁使用共享模式;写锁使用独占模式,换句话说,读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的
- ReetrantReadWriteLock读写锁的实现中,需要注意的,当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁
一般都会在finally中释放锁,保证在方法提前结束或出现 Exception 的时候,依然能正常释放锁。
// 读操作
public static void readFile(Thread thread) {
lock.readLock().lock();
boolean readLock = lock.isWriteLocked();
if (!readLock) {
System.out.println("当前为读锁!");
}
try {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName() + ":正在进行读操作……");
}
System.out.println(thread.getName() + ":读操作完毕!");
} finally {
System.out.println("释放读锁!");
lock.readLock().unlock();
}
}
// 写操作
public static void writeFile(Thread thread) {
lock.writeLock().lock();
boolean writeLock = lock.isWriteLocked();
if (writeLock) {
System.out.println("当前为写锁!");
}
try {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(thread.getName() + ":正在进行写操作……");
}
System.out.println(thread.getName() + ":写操作完毕!");
} finally {
System.out.println("释放写锁!");
lock.writeLock().unlock();
}
}
线程间通讯和交互
-
Thread.interrupt():温和式终结:不立即、不强制,相当于设置了一个中断状态。
interrupted() 和 isInterrupted():检查(和重置)中断状态,interrupted()会重置中断状态为false,isInterrupted()不会重置中断状态。
InterruptedException:如果在线程等待时中断,直接结束等待过程(因为等待过程什么也不会做,而interrupt() 的目的是让线程做完收尾工作后尽快终结,所以要跳过等待过程)
public void runTest() {
Thread thread = new Thread() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (Thread.interrupted()) {
// 收尾工作 Thread.interrupted()线程中断或重置,所以if条件只会进来一次
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 收尾工作 如果在睡眠中thread.interrupt()就会立即结束,进入InterruptedException,在这里也会重置中断状态
return;
}
}
}
};
thread.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();//中断状态
}
-
Object.wait() 和 Object.notify() / notifyAll()
wait() 和 notify() / notifyAll() 都需要放在同步代码块里
在未达到目标时 wait(),让出持有的监视moinitor对象,进入等待队列
用 while 循环检查
设置完成后 notifyAll(),唤醒等待队列中的线程去执行操作
public class WaitDemo implements TestDemo {
private String mName;
private synchronized void initName() {
mName= "kingcp";
notifyAll();
}
private synchronized void printName() {
while (mName== null) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("name: " + mName);
}
@Override
public void runTest() {
final Thread thread1 = new Thread() {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
printName();
}
};
thread1.start();
Thread thread2 = new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
initName();
}
};
thread2.start();
}
}
- Thread.join():让Thead线程插在目前运行的自己线程前⾯
- Thread.yield():暂时让出自己的时间片给 同优先级 的线程