一、线程,创建线程的第一种方式(继承方式):继承Thread类。
步骤:
1,自定义一个类继承Thread.
2,复写自定义类中的run方法,该方法就是新线程的入口函数。
3,创建自定义类对象,调用该对象的start方法。(该方法有两个作用,起动线程和调用run方法)
创建线程的第二种方式(实现方式):
步骤:
1,定义类实现Runnable接口。
2,覆盖Runnable接口中的run方法。(该方法即为新线程要调用的入口函数)
3,创建步骤1中类的对象。
4,通过Thread类建立线程对象,并把步骤2中创建的对象做为实际构造参数传入。
5,调用步骤4中所建对象的start方法。
二、继承方式与实现方式有什么区别呢?
实现方式的好处:避免了单继承的局限性。(在定义线程时建议使用实现方式)
三、static Thread currentThread():获取当前线程对象。
getName:获取线程名称。
设置线程名称:setName或者用构造方法。
四、Thread类有一个静态函数sleep,该函数声明了抛出异常,使用要用try{}catch{}处理,因为在实现方式中
接口Runnable中的run方法没有声明抛出异常,所以只能try不能抛。
五、关于多线程及其安全问题,如买票系统出现-1的票号。
六、java对多线程的安全问题提供了专业的解决方法,就是同步代码块和同步函数。
同步代码块:
synchronized(对象)//该对象可以是任一对象,只要是对象就OK。
{
需要被同步的代码
}
同步函数:
public synchronized void method(){}
七、线程同步的两个条件:
1,必须有两个以上线程,2,必须用同一个锁。
不同的代码块可以用同一个锁,同样能实现线程同步。
八、同步函数用的是哪一个锁呢?
函数需要被对象调用,那么函数都有一个所属对象引用,就是this,
所以同步函数使用的锁是this.
九、静态同步函数中不可定义this,那么它用的是哪一个锁呢?
静态函数进内存时,内存中没有本类对象,但是一定有该类对应字节码文件对象,
所以静态同步函数用的是字节码文件对象:类名.class,该对象的类型是Class
十、用同步代码时进行双重判断可提高效率如下代码:
class Single
{
private static s;
private Single(){}
public static Single getInstance()
{
if(s == null)
{
synchronized(Single.class)
{
if(s == null)
s = new Single();
}
}
return s;
}
}
十一、wait、notify、notifyall都使用在同步中,因为要对持有监视器(锁)的线程操作,所以要使用在同步中,
因为只有同步才具有锁。
为什么这些操作线程的方法要定义在Object类中呢?
因为这些方法在操作同步线程时,都必须要标识它们所操作线程所持有的锁,
只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒。
不可以对不同锁上的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object中。
十二、lock对象和Condition对象。
lock是一个接口,用其实现类(如:ReentrantLock类)定义一个对象:ReentrantLock lock = new ReentrantLock();
该接口有两个函数,其用法为:lock.lock();lock.unlock();
Condition对象由lock对象的newCondition方法创建,如:Condition condi = lock.newCondition();
Condition对象有三个函数,分别为:await()、signal()、signalAll().
十三、守护线程(用户线程):守护线程依赖于前台线程,当前台线程结束,守护线即跟着结束。
Thread类的一个方法setDaemon用于设置一个线程为守护线程,如:Thread t = new Thrad(r);t.setDaemon(true);
该方法必须在线程起动前调用。
十四、join,Thread类的成员方法。
当A线程执行到B线程的join方法时,A就会等待,等待B线程执行完后,A线程才会继续执行。
join用来临时加入线程执行。
十五、setPriority,Thread类的成员函数,用于设置线程优先级。
yield,Thread类的静态成员函数,暂停当前正在执行的线程对象,并执行其他线程。