一.线程与进程:
(一).进程:是一个正在执行中的程序。
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
(二)..线程
1含义:就是进程中的一个独立的控制单元(执行路径,执行情景)。
线程在控制着进程的执行。一个进程中至少有一个线程。Java VM启动时,只好有两个线程:jvm的主线程(这个线程运行的代码存在于main方法中)、jvm的垃圾回收线程。
2.线程的五种状态:
(1).新建:新建线程,
(2).就绪:线程争夺CPU的执行权,具有执行资格,但没有执行权,
(3).运行:争夺到CPU执行权的线程开始执行,具有执行资格和执行权,
(4).阻塞:通过sleep方法和wait方法使线程停止运行,sleep方法指定时间内就会醒来,wait方法必须要等待唤醒,两个方法没有执行资格和执行权,一旦醒来,会重新进入就绪状态。
(5).死亡:有两种形式,1是线程执行完毕后线程停止,2人为的通过stop方法使线程停止
3.如何在自定义的代码中,自定义一个线程呢?
(1).创建线程的第一种方式:继承Thread类。
步骤:
1).定义类继承Thread。
2).复写Thread类中的run方法。目的:将自定义代码存储在run方法。让线程运行。
3).调用线程的start方法,该方法两个作用:启动线程,调用run方法。(run方法,用于存储线程要运行的代码。
)
//如果直接运行对象.run();实际上是main线程在运行。
(2).创建线程的第二种方式:实现Runnable(接口)
步骤:
1).继承Thread类。
2).覆盖run方法。将线程要运行的代码定义其中。
3).创建Thread类的子类对象,其实就是在创建线程,调用start方法。
(3).实现方式(Runnable)和继承方式(Thread)有什么区别呢?
实现方式好处:避免了单继承的局限性。在定义线程时,建立使用实现方式。
两种方式区别:继承Thread:线程代码存放Thread子类run方法中。实现Runnable,线程代码存在接口的子类的run方法。
二.线程安全
(一).多线程出现安全问题原因:多线程具备随机性。因为是由cpu不断的快速切换造成的,就有可能会产生多线程的安全问题。
问题的几个关键点:
1.多线程代码中有操作共享数据。
2.多条语句操作该共享数据。
当具备两个关键点时,有一个线程对多条操作共享数据的代码执行的一部分。还没有执行完,另一个线程开始参与执行。
就会发生数据错误。
(二).解决方法(同步):当一个线程在执行多条操作共享数据代码时,其他线程即使获取了执行权,也不可以参与操作。Java就对这种解决方式提供了专业的代码。
1.同步的原理:就是将部分操作功能数据的代码进行加锁。
2.同步的表现形式:
1).同步代码块:同步代码块使用的锁是任意对象。
2).同步函数:同步函数使用的锁是this,对于static的同步函数,使用的锁不是this。是类名.class是该类的字节码文件对象。
3.同步的好处:解决了线程的安全问题。弊端:较为消耗资源,同步嵌套后,容易死锁。
(三).两种同步:
1.(synchronized代码块和函数):
/*
同步函数用的是哪一个锁呢?
函数需要被对象调用。那么函数都有一个所属对象引用。就是this。
所以同步函数使用的锁是this。
通过该程序进行验证。
使用两个线程来买票。
一个线程在同步代码块中。
一个线程在同步函数中。
都在执行买票动作。
*/
class Ticket implements Runnable
{
private int tick = 100;
Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(this)
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);
}
}
}
}
else
while(true)
show();
}
public synchronized void show()//this
{
if(tick>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);
}
}
}
class ThisLockDemo
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.flag = false;
t2.start();
//Thread t3 = new Thread(t);
//Thread t4 = new Thread(t);
//t3.start();
//t4.start();
}
}
2.(Lock唤醒对方线程):
/*
JDK1.5 中提供了多线程升级解决方案。
将同步Synchronized替换成现实Lock操作。
将Object中的wait,notify notifyAll,替换了Condition对象。
该对象可以Lock锁 进行获取。
该示例中,实现了本方只唤醒对方操作。
Lock:替代了Synchronized
lock
unlock
newCondition()
Condition:替代了Object wait notify notifyAll
await();
signal();
signalAll();
*/
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
// t1 t2
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_pro.await();//t1,t2
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);
flag = true;
condition_con.signal();
}
finally
{
lock.unlock();//释放锁的动作一定要执行。
}
}
// t3 t4
public void out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);
flag = false;
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.set("+商品+");
}
catch (InterruptedException e)
{
}
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
try
{
res.out();
}
catch (InterruptedException e)
{
}
}
}
}
(四):多线程的优先级和停止线程:
1.多线程的优先级:thread.t1.setPriority(int newPriority); //newPriority取值1-10
2.停止线程:
stop过时。原理:run方法结束。run方法中通常定义循环,指定控制住循环线程即可结束。
1,定义结束标记。
2,当线程处于了冻结状态,没有执行标记,程序一样无法结束。
这时可以循环,正常退出冻结状态,或者强制结束冻结状态。
强制结束冻结状态:interrupt();目的是线程强制从冻结状态恢复到运行状态。
但是会发生InterruptedException异常。