当Java虚拟机启动的时候就会有一个非后台线程去执行main方法!
java.lang
类 Thread
java.lang.Thread
所有已实现的接口:
public class Thread
extends Object
implements Runnable
线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。
当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:
- 调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。
- 非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。
创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。例如,计算大于某一规定值的质数的线程可以写成:
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
然后,下列代码会创建并启动一个线程:
PrimeThread p = new PrimeThread(143);
p.start();
创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
然后,下列代码会创建并启动一个线程:
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。
Thread.getName()返回线程的名字!
Thread.setDemaon()方法用来设置将一个线程设置为后台线程!
将一个线程设置为后台线程,必须在这个线程调用start()方法之前,
如果所有线程都是后台线程,那么java虚拟机将退出!
Yiled方法可以是当前线程放弃执行权力!
线程优先级范围是1到10 10为最高
Thread定义了三个常量!
调用yiled方法的时候,将这个线程进入等待状态,如果一个具有高优先级线程,搞优先级线程将会一直占据CPU。
Java不支持时间片轮转,它只是支持高优先调用
第二种方法是实现Runable接口,
将实现了Runable接口的类的一个实例作为Thread构造函数的参数
然后再调用start()方法!
获取当前线程的名字Thread.currentThread获取当前线程的实例!
两种方法选择
实现Runable接口,一方面可以避免多重继承的情况,java不支持,另外一方面也可以方便实现共享变量!可以实现贡献变量
不过共享变量可以通过内部类来是实现,内部类实现Runable接口,提供run方法
在通过一个方法向外面提供Thread对象!
同步的两种方式:同步块和同步方法
每一个对象都有一个监视器,或者叫做锁。
同步方法利用的是this所代表的对象的锁。
每个class也有一个锁,是这个class所对应的Class对象的锁。
同步块:
Object o = new Object()
Synchronized(o)//进入的时候会把对象O的锁给关上,大括号出来的时候把锁给打开
{
}
这个同步块会出现问题
int tickets = 100;
Object o = new Object();
public void run()
{
while(tickets>0)
{
synchronized(o)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" sell ticket:"+tickets);
tickets--;
}
}
当最后一张票的时候tickets=1,tickets,三个线程都一样,在进入关键区之前都会进行判断tickets是否大于1,结果都是true,所以进入关键代码段,但是一个时候只能有一个线程执行,其余线程就等待,这个线程执行完之后tickets=0,这个时候第二个线程获得进入关键代码段权力,再买一张tickets为-1,第三个线程就买-2票了,这个例子告诉我们,要把共享变量保护起来而不仅仅是在修改的时候,判断时候也要保护起来
同步方法:
class SellThread implements Runnable
{
int tickets = 100;
Object o = new Object();
public void run()
{
while(true)
{
sell();
}
}
public synchronized void sell()
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" sell ticket:"+tickets);
tickets--;
}
}
}
采用同步方法,写一个方法synchronized,然后再run里面调用这个函数!也可以实现同步!
同步方法是对 this对象进行加锁,返回的时候对this监视器进行解锁!
线程调用start()之后并不会立即启动,主要是因为调用start的主线程时间片没有结束!
Wait()和notify()
必须在一个同步块或者同步方法中调用!
wait和notify要在同一个对象的等待队列删除,添加线程!
yiled线程调用一个可运行的状态,当前运行线程变为一个可运行的线程Runnable状态!
Stop会解锁所有线程的监视器,会导致线程状态不一致
已经停用
Suspend,resume已经停用
如果要终止一个线程可以调用
1, 设置一个变量boolrsm
Run方法
{
While(!bStop)
{
…….
}
Void syop()
{
Bstop=false;
}
}
Thread.Interrupt(),那么wait方法会抛出InterruptedException e异常