线程是系统调度的最小单元,一个进程可以包含多个线程,作为任务的真正运作者,有自己的栈(Stack)、寄存器(Register)、本地存储(Thread Local)等,但是会和进程内其他线程共享文件描述符、虚拟地址空间等。在具体实现中,线程还分为内核线程、用户线程,Java 的线程实现其实是与虚拟机相关的。
创建线程方式
public class ThreadImpl extends Thread {
}
public class MyThread implements Runnable {
private int ticket;
private Lock lock = new ReentrantLock();
public MyThread(int ticket) {
this.ticket = ticket;
}
@Override
public void run() {
print();
}
public void print() {
lock.lock();
try {
while (ticket > 0) {
System.out.println("ticket==" + ticket);
ticket--;
}
} catch (Exception e) {
System.out.println("Exception==" + e);
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread(5);
new Thread(myThread).start();
new Thread(myThread).start();
}
}
public class CallTask implements Callable {
private int upperBounds;
public CallTask(int upperBounds) {
this.upperBounds = upperBounds;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= upperBounds; i++) {
sum += i;
}
return sum;
}
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
try {
int sum = (int) service.submit(new CallTask((int) (Math.random() * 100))).get();
System.out.println("sum==" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
-
结束线程的三种方法
- run()方法执行完正常退出
- 调用interrupt()方法
- 使用stop方法强行终止线程(不推荐使用,Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃,使用它们是极端不安全的!)
常用锁处理
-
synchronized :
- 对象锁:非静态synchronized方法,同个对象相互排斥,不同类对象不互斥
- 类锁:静态synchronized方法和synchronized代码块方法, 不同类对象互斥,同个对象也互斥。
public class LockThread implements Runnable {
private Integer key = 0;
@Override
public void run() {
synchronized (this) {
key++;
System.out.println(Thread.currentThread().getName() + ":" + key);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace(); }
}
}
public static void main(String[] args) {
LockThread lockThread = new LockThread();
for (int i = 0; i < 100; i++) {
new Thread(lockThread, "thread" + i).start();
}
}
}
public class LockThread implements Runnable {
private Integer key = 0;
private Lock lock = new ReentrantLock();
@Override
public void run() {
lock.lock(); //获取锁
try {
key++;
System.out.println(Thread.currentThread().getName() + ":" + key);
Thread.sleep(5);
} catch (Exception e) {
} finally {
lock.unlock(); //释放锁
}
}
public static void main(String[] args) {
LockThread lockThread = new LockThread();
for (int i = 0; i < 100; i++) {
new Thread(lockThread, "thread" + i).start();
}
}
}
volatile和synchronized的区别
|
volatile |
synchronized |
作用域 |
变量 |
方法,代码块 |
操作性 |
仅保证可见性,有序性 |
可以保证可见性和原子性 |
线程堵塞状态 |
不会造成线程的阻塞 |
可能会造成线程的阻塞 |
Lock和synchronized的区别
|
Lock |
synchronized |
使用区别 |
类 |
关键字 |
作用域 |
代码块 |
代码块,方法 |
释放锁 |
需要finally()方法手动释放锁 |
执行完自动释放锁 |
锁类型 |
可重入,可判断,可公平(两者皆可) |
可重入,不可中断,非公平 |
依托实现 |
Java代码控制 |
JVM执行 |
性能 |
高竞争场景中表现可能优于synchronized |
在低竞争场景中表现可能优于 ReentrantLock |
sleep()和wait()的区别
|
sleep |
wait |
|
睡眠时,保持对象锁,仍然占有该锁 |
睡眠时,释放对象锁 |
作用域 |
任何地方调用 |
只能在同步方法或同步块中使用 |
时间 |
指定时间后唤醒 |
只有等notify()/notifyAll()通知有才能唤醒 |
并发高效类
实际开发中Java封装了一些解决高并发的类包(java.util.concurrent包),常用的如下:
- AtomicInteger
提供一种线程安全的加减操作
- AtomicBoolean
- AtomicLong
- AtomicReference
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray