一、死锁问题
同步弊端
效率低
如果出现了同步嵌套,就容易产生死锁问题
死锁问题
是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
public class MyLock {
public static final Object obj1=new Object();
public static final Object obj2=new Object();
}
public class DieLock extends Thread {
private boolean flag;
public DieLock(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if(flag){
synchronized (MyLock.obj1){
System.out.println(" if obj1");
synchronized (MyLock.obj2){
System.out.println("if obj2");
}
}
}else{
synchronized (MyLock.obj2){
System.out.println("else obj2");
synchronized (MyLock.obj1){
System.out.println("else obj1");
}
}
}
}
}
public class DieLockTest {
public static void main(String[] args) {
DieLock dieLock1 = new DieLock(true);
DieLock dieLock2 = new DieLock(false);
dieLock1.start();
dieLock2.start();
}
}
二、线程间通信
针对同一个资源的操作有不同种类的线程
public class Student {
String name;
int age;
boolean flag;
}
public class SetThread implements Runnable {
private Student s;
int i=0;
public SetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while(true){
synchronized (s){
if(s.flag){
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i%2==0){
s.name="张三";
s.age=18;
}else{
s.name="李四";
s.age=30;
}
i++;
s.flag=true;
s.notify();
}
}
}
}
public class GetThread implements Runnable {
private Student s;
public GetThread(Student s) {
this.s = s;
}
@Override
public void run() {
while(true){
synchronized (s){
if(!s.flag){
try {
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(s.name+"==="+s.age);
s.flag=false;
s.notify();
}
}
}
}
public class Test {
public static void main(String[] args) {
Student s = new Student();
SetThread st = new SetThread(s);
GetThread gt = new GetThread(s);
Thread t1 = new Thread(st);
Thread t2 = new Thread(gt);
t1.start();
t2.start();
}
}
三、线程的状态转换图
四、线程组
Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
默认情况下,所有的线程都属于主线程组。
public final ThreadGroup getThreadGroup()
我们也可以给线程设置分组
Thread(ThreadGroup group, Runnable target, String name)
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class ThreadGroupTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable,"张三");
Thread t2 = new Thread(myRunnable,"李四");
ThreadGroup tg1 = t1.getThreadGroup();
ThreadGroup tg2 = t2.getThreadGroup();
String name1 = tg1.getName();
String name2 = tg2.getName();
System.out.println(name1);
System.out.println(name2);
}
}
public class ThreadGroupTest2 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
ThreadGroup tg = new ThreadGroup("新组");
Thread t1 = new Thread(tg, myRunnable, "张三");
Thread t2 = new Thread(tg,myRunnable,"李四");
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
}
}
五、线程池
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
DK5新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newCachedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
public class ExecutorsTest {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.shutdown();
}
}
六、匿名内部类方式使用多线程
public class ThreadTest {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"="+i);
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"="+i);
}
}
}).start();
}
}
七、定时器
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能
Timer
public Timer()
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task,long delay,long period)
TimerTask
public abstract void run()
public boolean cancel()
public class TimerTest {
public static void main(String[] args) {
Timer t = new Timer();
t.schedule(new MyTask(t),3000);
}
}
class MyTask extends TimerTask{
private Timer t;
public MyTask(Timer t) {
this.t = t;
}
public MyTask() {
}
@Override
public void run() {
System.out.println("boom");
t.cancel();
}
}