1多线程创建方式
方法一:继承java.lang.Thread, 重写run()方法
Thread本质上也是实现了Runnable接口的一个实例,并且,启动线程的唯一方法就是通过Thread类的start()方法。调用start()方法,再重写run()方法就可以启动新线程并执行自己定义的run()方法。调用start()方法后并不是立即执行多线程代码,而是使得该线程变为可运行态,什么时候运行多线程代码是由操作系统决定的。
class MyThread extends Thread {
private int tid;
public MyThread(int tid) {
this.tid = tid;
}
@Override
public void run() {
try {
for (int i = 0; i < 10; ++i) {
Thread.sleep(1000); //每隔1000睡眠一下
System.out.println(String.format("%d:%d", tid, i));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//测试
public class Main {
public static void main(String[] args) {
new MyThread().start();
}
}
方法二:实现java.lang.Runnable接口,重写run()方法
代码一:
public static void testThread() {
for (int i = 0; i < 10; ++i) {
final int finalI = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int j = 0; j < 10; ++j) {
Thread.sleep(1000);
System.out.println(String.format("T2 %d: %d:", finalI, j));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
//测试
public static void main(String[] argv) {
testThread();
}
代码二:
① 自定义类并实现Runnable接口,实现run()方法。
② 创建Thread方法,用实现Runnable接口的对象作为参数实例化该Thread对象。
③ 调用Thread的start()方法。
class MyThread implements Runnable {
public void run(){
System.out.println(“Thread body”);
}
}
public class Test{
public static void main(String[] args){
MyThread thread = new MyThread();
Thread t = new Thread(thread);
t.start();
}
}
方式三:实现Callable接口,重写call()方法
属于Executor框架中的功能类,与Runnable接口功能类似,但提供了比Runnable接口更强大的功能,主要表现在:
① Callable可以在任务结束后提供一个返回值,Runnable不能。
② Callable中的call()方法可以抛出异常,Runnable的run()方法不能。
③ 运行Callable可以拿到一个Future对象,表示异步计算的结果,提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下,就可以使用Future来监视目标线程调用call()方法的情况,当调用Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法结束返回结果。
2 Synchronized 内置锁
当Synchronized用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码,而这段代码也被称为临界区。
// synchronized(obj)锁住相应的代码段
public static void testSynchronized1() {
synchronized (obj) {
try {
for (int j = 0; j < 10; ++j) {
Thread.sleep(1000);
System.out.println(String.format("T1 %d", j));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void testSynchronized2() {
synchronized (new Object()) {
try {
for (int j = 0; j < 10; ++j) {
Thread.sleep(1000);
System.out.println(String.format("T2 %d", j));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//测试
//参数 obj与new Object()为不同对象,因此两个内置锁互不干扰
//参数相同时(都为obj),两个内置锁互相干扰,一个执行完才执行另一个
public static void testSynchronized() {
for (int i = 0; i < 10; ++i) {
new Thread(new Runnable() {
@Override
public void run() {
testSynchronized1();
testSynchronized2();
}
}).start();
}
}
3 BlockingQueue 同步队列
//remove实现(implements Runnable接口,实现 run()方法)
class Consumer implements Runnable {
private BlockingQueue<String> q;
public Consumer(BlockingQueue<String> q) {
this.q = q;
}
@Override
public void run() {
try {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + q.take());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//insert实现
class Producer implements Runnable {
private BlockingQueue<String> q;
public Producer(BlockingQueue<String> q) {
this.q = q;
}
@Override
public void run() {
try {
for (int i = 0; i < 100; ++i) {
Thread.sleep(1000);
q.put(String .valueOf(i));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//测试
public static void testBlockingQueue() {
BlockingQueue<String> q = new ArrayBlockingQueue<String>(10);
new Thread(new Producer(q)).start();
new Thread(new Consumer(q), "Consumer1").start();
new Thread(new Consumer(q), "Consumer2").start();
}
public static void main(String[] argv) {
testBlockingQueue();
}
结果:两条线程交替消费
4 ThreadLocal
ThreadLocal:线程局部变量,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。即使是一个static成员,每个线程访问的变量是不同的。常见于web中存储当前用户到一个静态工具类,在线程的任何地方都可以访问到当前线程的用户。利用ThreadLocal可以防止线程访问同一个变量时发生混乱。
//ThreadLocal变量和普通变量
private static ThreadLocal<Integer> threadLocalUserIds = new ThreadLocal<>();
private static int userId;
//利用ThreadLocal存储用户信息
@Component
public class HostHolder {
private static ThreadLocal<User> users = new ThreadLocal<User>();
public User getUser() {
return users.get();
}
public void setUser(User user) {
users.set(user);
}
public void clear() {
users.remove();;
}
}
5 Executor
Executor :提供一个运行任务的框架,将任务和如何运行任务解耦,常用于提供线程池或定时任务服务.
// Executor
public static void testExecutor() {
//ExecutorService service = Executors.newSingleThreadExecutor();单个线程
ExecutorService service = Executors.newFixedThreadPool(2);//两个线程
service.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; ++i) {
try {
Thread.sleep(1000);
System.out.println("Executor1:" + i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
service.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; ++i) {
try {
Thread.sleep(1000);
System.out.println("Executor2:" + i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
部分结果:交替执行
6 Future
Future:返回异步结果、阻塞等待返回结果、获取线程中的exception
//测试
public static void testFuture() {
ExecutorService service = Executors.newSingleThreadExecutor();
Future<Integer> future = service.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
throw new IllegalArgumentException("异常");
}
});
service.shutdown();
try {
//get()方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线
//程,直到任务执行完毕
System.out.println(future.get());
} catch (Exception e) {
e.printStackTrace();
}
}
7 AtomicInteger
AtomicInteger:高并发的情况下,i++无法保证原子性,往往会出现问题,所以引入AtomicInteger类。
//普通变量和AtomicInteger变量的定义
private static int counter = 0;
private static AtomicInteger atomicInteger = new AtomicInteger(0);
//普通变量结果没有100,达到97
public static void testWithoutAtomic() {
for (int i = 0; i < 10; ++i) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
for (int j = 0; j < 10; ++j) {
counter++;
System.out.println(counter);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
//AtomicInteger变量可以达到100
public static void testWithAtomic() {
for (int i = 0; i < 10; ++i) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
for (int j = 0; j < 10; ++j) {
System.out.println(atomicInteger.incrementAndGet());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
public static void testAtomic() {
testWithAtomic();
}