--------------------- android培训、java培训、java学习型技术博客、期待与您交流! ----------------------
进程:一个正在执行的程序,用于标示空间,用于封装控制单元
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元
线程:进程中的一个独立的控制单元。线程在控制着进程的执行
一个进程中至少一个线程
Java虚拟机启动时会有一个进程,该进程中至少一个线程负责java程序的执行,而这个线程存在于main方法中
严格来讲虚拟机是多线程的,比如主线程和垃圾回收线程
创建一个线程的方法:继承thread 重写run 实现runnable
创建一个实例就是定义一个线程
MyThread m = new MyThread();
//该方法有两个作用:启动线程,调用run方法
m.start();
实际上,同一时间,CPU只能执行一个进程中的一个线程,多线程执行时有随机性
为什么重写run方法:如果未覆盖,start中执行的run方法时父类的run方法,run方法其实就是线程要执行的代码,例如主线程中要执行的代码存于main方法中
只有start方法才能开启线程
Wait和sleep的区别,sleep在一段时间后会自动执行,而wait无法继续执行,只能主动还行notify。Stop表示消亡线程
主动结束:调用stop
被动结束:程序执行完
阻塞状态,某个进程再等CPU执行权的状态叫阻塞状态,有执行资格
冻结状态,sleep,wait,表示线程放弃了执行资格
线程的四个状态:冻结,消亡,运行,阻塞
setName,getName设置获取名称
线程有自己默认的名称 可以通过new的时候在后面传入线程名称来修改
卖票程序
静态的生命周期太长,所以不定义静态
线程第二种实现方式:实现runnable接口
<!--[if !supportLists]-->1. <!--[endif]-->实现runnable接口
<!--[if !supportLists]-->2. <!--[endif]-->重写run方法
<!--[if !supportLists]-->3. <!--[endif]-->实例化一个对象
<!--[if !supportLists]-->4. <!--[endif]-->New一个Thread类对象,并将上面实例化的对象传进去(自定义的run方法所属的是runnable的实现类,所以要让线程去执行指定对象的run方法)
<!--[if !supportLists]-->5. <!--[endif]-->调用Thread类对象的start方法
接口和父类实现线程的区别:就是实现和继承的区别 即功能性扩展
接口的run方法存在于接口的子类中,而继承则存在于Thread的子类中
publicclass MySecondThrad {
publicstaticvoid main(String[] args) {
//只有thread类或其子类才能开启线程
test m = new test();
Thread t1 = new Thread(m);
Thread t2 = new Thread(m);
Thread t3 = new Thread(m);
Thread t4 = new Thread(m);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class test implements Runnable
{
privateintticket = 100;
@Override
publicvoid run() {
while(true)
{
if(ticket > 0)
{
System.out.println("ticket"+ticket--);
}
}
}
}
Run方法中的异常必须捕捉不能抛
多线程的安全问题:多条线程争先执行代码,导致共享数据的错误
同步代码块:优点安全缺点消耗资源
Synchronized(对象)
{
}
对象如同锁,持有锁的进程可以执行,没有持有锁的线程即使获得了执行权也无法执行
同步的前提
<!--[if !supportLists]-->1. <!--[endif]-->必须要有两个以上的线程
<!--[if !supportLists]-->2. <!--[endif]-->必须是多个线程使用同一个锁
不是所有的run方法里面的代码都要放在同步代码块中
判断哪些代码该同步:
<!--[if !supportLists]-->a) <!--[endif]-->明确哪些代码是多线程代码
<!--[if !supportLists]-->b) <!--[endif]-->明确哪些是共享数据
<!--[if !supportLists]-->c) <!--[endif]-->明确哪些代码操作共享数据
同步函数默认调用this这个锁,如何验证
如果同步函数被静态修饰后,锁不再是this而是类对象(字节码文件对象)
单例设计模式
/**
* 饿汉式
*/
publicstaticfinal SingleDemo s = new SingleDemo();
private SingleDemo(){}
publicstatic SingleDemo getInstance(){
returns;
}
懒汉式
/**
* 懒汉式用于实例的延迟加载。
* 懒汉式加锁效率较低,
*/
publicstatic SingleDemo s = null;
private SingleDemo() {
}
publicstatic SingleDemo getInstance()
{
if(null == s)
{
synchronized(SingleDemo.class)
{
if(null == s)
{
s = new SingleDemo();
}
returns;
}
}
else
returns;
}
}
死锁
class tryDeadLock implements Runnable
{
Boolean b ;
public tryDeadLock(Boolean b)
{
this.b = b;
}
@Override
publicvoid run() {
while(true)
{
if(b){
synchronized(lock.l1)
{
synchronized(lock.l2)
{
System.out.println("111");
}
}
}
else{
synchronized(lock.l2)
{
synchronized(lock.l1)
{
System.out.println("222");
}
}
}
}
}
}
class lock{
static lock l1 = new lock();
static lock l2 = new lock();
}
publicclass DeadLock {
publicstaticvoid main(String[] args) {
tryDeadLock t1 = new tryDeadLock(true);
tryDeadLock t2 = new tryDeadLock(false);
Thread t3 = new Thread(t1);
Thread t4 = new Thread(t2);
t3.start();
t4.start();
}
}
多线程通信:多个线程操作同一个资源
等待唤醒机制
Wait notify notifyAll都用在同步中,这些方法必须由监视器调用即锁对象
锁是任意对象,所以定义在了object中
只有同步才有锁的概念
为甚么定义在object中,因为这些方法在操作线程时,必须标记所操作的对象只有的锁,只有同一个锁上的被等待线程可以被同一个锁上的notify唤醒。等待和唤醒必须是同一把锁