一、线程和进程
1.一个应用程序就是一个进程,一个进程中可以产生多个线程
2.进程之间的通信非常麻烦,而线程非常方便
3.进程是独享资源,即每个进程都有独立的内存空间,而线程是共享它所属的进程的资源。
4.进程结束,则这个进程所产生的所有线程也会被销毁
二、Java线程的处理方式
1、继承Thread类(两种方式):
a.外部类:
实例:
package thread;
/**
* 多线程
*
* @author ydk52
*
*/
public class Test4 {
public static void main(String[] args) {
System.out.println("主线程运行开始....");
System.out.println("当前活跃度:" + Thread.activeCount());
// 调用线程类
MyTimer1 myTimer1 = new MyTimer1();
myTimer1.start();// 启用线程,这个时候会自动调用这个线程类中的run()方法
try {
myTimer1.join();// 等待MyTimer1执行完再继续向下执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("嘻嘻...");
}
}
class MyTimer1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);// 休眠1s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i + 1);
System.out.println("当前活跃度:" + Thread.activeCount());
}
}
}
b.匿名内部类:
package thread;
/**
* 多线程
*
* @author ydk52
*
*/
public class Test3 {
public static void main(String[] args) {
/*//匿名内部类
Thread t=new Thread(){
public void run() {
for(int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i+1);
}
};
};
t.start();//启用线程
*/
//匿名内部类2
new Thread(){
public void run() {
for(int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i+1);
}
};
}.start();
}
}
2、实现Runnable接口
实例:
package thread;
import java.util.Random;
/**
* 多线程
*
* @author ydk52
*
*/
public class Test2 {
public static void main(String[] args) {
// 调用线程类
MyTimer2 t = new MyTimer2();
Thread t1=new Thread(t, "线程一");
Thread t2=new Thread(t, "线程二");
t1.start();
t2.start();
}
}
/**
* 声明一个定时任务
* @author ydk52
*
*/
class MyTimer2 implements Runnable {
/*@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);// 休眠1s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i + 1);
System.out.println("当前活跃度:" + Thread.activeCount());
}
}*/
private int num=10;
@Override
public void run() {
while (num>0) {
System.out.println(Thread.currentThread().getName()+":"+num--);
try {
Thread.sleep((long)(Math.random()*100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3、线程的主要任务——处理耗时的操作
4、Thread类与Runnable之间的关系
a、Thread类实现了Runnable接口
b、Runnable可以避免Thread类方式由于Java单继承的限制带来的缺陷
c、Runnable代码可以被线程共享,适合于多个线程处理同一个资源的情况
四、线程的分类
1、主线程
2、守护线程:
a、又称之为精灵线程
b、通过setDaemon(true),将一个线程设置为守护线程
c、其它线程运行完成,则守护线程也就over
3、子线程
五、线程的属性
1、id
2、name
3、priority来设置或获取线程的优先级->1-10,默认为5
4、ThreadGroup线程组
六、线程扩展
1、重排序问题
2、as-if-serial问题
3、volatile实现可见性
七、死锁
1、产生的原因:
由于竞争资源或者由于彼此通信而造成的一种阻塞现象。通俗的说就是彼此等待对方的资源。
2、差生死锁的四个条件
a、互斥条件:一个资源每次只能被一个进程或线程使用
b、请求和保持条件:一个进程或线程因请求资源而阻塞时,对已获得的资源保持不放
c、不剥夺条件:进程或线程已获得的资源,在未使用完之前,不能强制剥夺
d、循环等待条件:若干进程或线程之间形成头尾相接的循环等待资源关系
八、如何控制线程
1、sleep:
这是一个静态方法,Thread.sleep(),有可能会抛出异常,需要try{}catch(){},休眠后,线程进入阻塞->就绪->运行。
2、优先级
3、join:在一个线程中调用另一个线程的join(),则当前线程阻塞,让另一个线程先执行。当另一个线程执行完后,当前线程才继续执行,跟优先级无关。
4、synchronized:
同一时刻只允许一个线程访问其中的资源。主要解决多线程操作一个资源时,数据不一致的问题。属于同步方法、也可以生成同步块。
5、线程的生命周期