线程简介:
线程是一个程序内部的顺序控制流。
线程和进程的区别:
每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。
线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换的开销小。
多进程:
在操作系统中能同时运行的多个任务。
多线程:
在同一个应用程序中有多个顺序流同时执行。
Java的线程是通过java.lang.Thread类实现的;JVM启动时会有一个由主方法所定义的线程;可以通过创建Thread的实例来创建新的线程;每个线程都是通过某个特定的Thread对象所对应的run()方法来完成其操作的,run()方法称为线程体。
线程的创建与启动:
第一种:
1.定义线程类target实现Runnable接口(使用Runnable接口可以为多个线程提供共享数据),其中Runnable中只有一个方法public void run();
2.Thread my Thread = new Thread(target);
3.在实现Runnable接口的类的run()方法定义中可以使用Thread的静态方法(currectThread()方法用于获取当前线程的引用)。
第二种:
1.可以定义一个Thread的子类并重写其run()方法:class MyThread extends Thread{ public void run(){ } } ;
2.然后生成该类的对象。
线程状态的转换:
阻塞解除
<-----------------
调度 导致阻塞的事件
<---- ---->*阻塞状态
*创建 *就绪状态 *运行状态 *终止
----> ----> ---->
start 调度 运行结束*标记为线程状态,箭头表示转换过程。
线程控制的基本方法:
isAlive() 判断线程是否还活着,即线程还未终止(上面的阻塞、就绪、运行三个状态)
getPriority() 获得线程的优先级
setPriority() 设置线程的优先级
Thread.sleep() 使当前线程进入休眠状态,并指定睡眠的毫秒数
join() 将当前线程与被调用该方法的线程合并,即等待该线程结束,在回复当前线程的运行
yield() 让出cpu,当前线程进入就绪队列等待调度
wait() 当前线程进入对象的wait pool
notify()/notifyAll() 唤醒对象的wait pool中的一个/所以等待线程
join的例子:
public class TestJoin {
public static void main(String[] args) {
MyThread2 t1 = new MyThread2("abcde");
t1.start();
try {
t1.join();
} catch (InterruptedException e) {}
for(int i=1;i<=10;i++){
System.out.println("i am main thread");
}
}
}
class MyThread2 extends Thread {
MyThread2(String s){
super(s);
}
public void run(){
for(int i =1;i<=10;i++){
System.out.println("i am "+getName());
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
只有执行完了t1的run()方法时才会继续执行main()方法。
Java的优先级别:
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照线程的优先级决定应调用哪个线程来执行;线程的优先级用数字来表示,范围从1到10,一个线程的缺省优先级是5。
Thread.MIN_PRIORITY = 1
Thread.MAX_PRIORITY = 10
Thread.NORM_PRIORITY = 5
线程同步:
在Java语言中,引入对象互斥锁的概念,保证共享数据操作的完整性;每个对象都对应于一个可以成为互斥锁的标记;这个标记保证在任意时刻,只有一个线程访问该对象;关键字synchronized用来与对象的互斥锁相联系;当某个对象的synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
synchronized的用法:
synchronized (this) {
}
synchronized还可以放在方法生声明中,表示整个方法为同步方法:
public synchronized void add(String name){
}
无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
public class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
public void run(){
timer.add(Thread.currentThread().getName());
}
}
class Timer{
private static int num = 0;
public synchronized void add(String name){
//synchronized (this) {
num ++;
try {Thread.sleep(1);}
catch (InterruptedException e) {}
System.out.println(name+", 你是第"+num+"个使用timer的线程");
//}
}
}
需要注意的是:
1.两个线程不可同时执行一个类中被声明了synchronized的方法;
2.当一个线程正在访问一个类的其中一个被声明为synchronized方法的方法的时候,其他线程可以访问该类中没有声明为synchronized的方法;
3.一个类中不可以同时有多个被声明为synchronized的方法被执行(一个对象只有一个互斥锁,需要等待另外一个线程释放互斥锁后才可以执行)。
Wait和sleep的区别:
Wait时,别的线程可以访问锁定的对象(调用wait的方法的时候必须锁定该对象)。
Sleep时,别的线程不可以访问锁定对象。
死锁的例子:
public class TestDeadLock implements Runnable {
public int flag = 1;
static Object o1 = new Object(), o2 = new Object();
public void run() {
System.out.println("flag=" + flag);
if(flag == 1) {
synchronized(o1) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o2) {
System.out.println("1");
}
}
}
if(flag == 0) {
synchronized(o2) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o1) {
System.out.println("0");
}
}
}
}
public static void main(String[] args) {
TestDeadLock td1 = new TestDeadLock();
TestDeadLock td2 = new TestDeadLock();
td1.flag = 1;
td2.flag = 0;
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.start();
t2.start();
}
}
来源:https://www.cnblogs.com/mosquito-woo/p/3920348.html