一,线程的特性
1.抢占式运行
给程序 分配CPU,按照时间片来执行,单位时间片抢占式执行的。随机抢占的
2.资源共享
同一个进程,有多个线程,这个多个线程是可以共享同一个数据的
证明线程的抢占式运行
class A implements Runnable{
@Override
public void run() {
for (int i =1 ; i <10 ; i++) {
for (int j = 1; j <=i ; j++) {
System.out.print(i+"*"+j+"="+i*j+" ");
}
System.out.println();
}
}
}
class B implements Runnable{
@Override
public void run() {
for (int i = 1; i <30 ; i++) {
for (int j = 1; j <30-i ; j++) {
System.out.print(" ");
}
for (int k= 1; k <=i; k++) {
System.out.print("*");
}
System.out.println();
}
}
}
public class Test {
public static void main(String[] args) {
new Thread(new B()).start();
new Thread(new A()).start();
}
}
而他打印出来的结果是
这就说明了,线程A和线程B之间的运行是抢占式的,谁抢到谁就执行
线程下面的一些常用方法
1. start()方法
我们去调用,想让线程去执行的方法
线程创建以后,并不会自动运行,需要我们手动的调用start把线程的状置为为就绪状态;但不一定马上就被运行,得等到CPU分配时间片以后,才会运行。
线程状态:调用start()方法,创建—>就绪
2. run()方法
cpu去调用,线程被真正 执行的方法
线程真正要执行的逻辑,当一个线程被分配到cpu资源,开始启动就会调用run方法执行
线程状态:就绪—>运行
3. join()方法:释放锁
概念:join方法,当前线程调用某线程.join()时会使当前线程等待某线程执行完毕再结束,底层调用了wait,释放锁;
t1和t2两个线程,如果在t1线程里面调用了t2.join(),则t1线程会进行等待状态,t2运行结束以后,才会继续运行t1。这样可以保证线程的先后顺序。
线程状态:调用join()方法,线程从运行态—>阻塞态
4. wait()方法:释放锁 【wait notify notifyAll本质上是Object类的方法】
注意:wait() 其实是Object类里面的方法,调用对象的wait方法导致线程放弃CPU的执行权,同时也放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool)
概念:wait()使当前线程阻塞,使当前线程回到线程池中等待,释放锁,当被其他线程使用notify,notifyAll 唤醒时进入就绪状态;(前提是必须先获得锁)
一般配合synchronized来使用,即:在 synchronized 同步代码块里使用 wait()、notify() / notifyAll() 方法,wait方法由当前所有的local对象里面调用,this.wait(),必须被try catch包围,保证即使异常中断也可以使wait等待的线程唤醒。执行了wait方法,需要被别的线程通过同一个对象的notify方法唤醒。
线程状态:调用wait()方法,线程从运行态—>阻塞态
总结:wait notify notifyAll都必须在持有有锁的代码中
5. notify() / notifyAll()方法:释放锁(不是立刻释放)
概念:
obj.notify:随机唤醒对象obj的某个wait线程,使被唤醒的线程进入就绪状态。
obj.notifyAll:唤醒对象obj的所有wait线程,使被唤醒的线程进入就绪状态。