Java多线程与线程安全

时间:2022-12-31 04:17:39



一.线程与进程:

(一).进程:是一个正在执行中的程序。

                 每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。

 

(二)..线程

 

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异常。