区别:
1.进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统进行资源分配和调度的一个独立单位。
2.线程是进程的一个实体,是CPU调度和分配的基本单位。线程基本不拥有系统资源,与同一个进程的其他线程共享进程中所拥有的所有资源。
联系:
1.一个进程可以包括多个线程。
应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
第一种方式:使用Runnable接口创建线程
1.可以实现多个线程资源共享
2.线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法
第二种方式:直接继承Thread类创建对象
1.Thread子类无法再从其它类继承(java语言单继承)。
2.编写简单,run()方法的当前对象就是线程对象,可直接操作。
1、创建状态:线程对象已经创建,还没有在其上调用start()方法。
2、可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。
3、运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。
4、阻塞状态:这是线程有资格运行时它所处的状态。如执行了join/sleep/wait方法,会让出CPU,只有当引起阻塞的原因消除时,线程才能转入就绪状态。
5、死亡态:当线程的run()方法完成时就认为它死去。或者抛出一个未捕获到的Exception或Error。
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
原因是由于不同线程获取到资源时进行运算,但未来得及写入时,线程改变,则另外线程读入的资源就是错误,导致所有线程写入读入不同步。
解决办法:
使用监视器,使用关键字synchronized监视同步代码块,当一个线程获得监视权限时,别的线程就无法获得,保证每时每刻只有一个线程调用某一方法
线程同步通信是希望实现两个或多个线程之间的某种制约关系
实现:首先是用监视器synchronized来保证每次只有一个线程调用方法,其次引入一个boolean型标志来判断该线程是否执行或wait,两个线程时使用notify(),多个线程时用notifyAll()来让出监视器并唤醒其他线程。这样就实现了线程之间的关系。
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。
class Account
{
volatile private int value;
void put(int i)
{
synchronized(this) {
value = value + i;
System.out.println("存入"+i+" 账上金额为:"+value);
}
}
synchronized int get(int i)
{
if (value>i)
value = value - i;
else
{ i = value;
value = 0;
}
System.out.println("取走"+i+" 账上金额为:"+value);
return i;
}
}
class Save implements Runnable
{
int a=2000;
private Account a1;
public Save(Account a1)
{
this.a1 = a1;
}
public void run()
{
while(a-->0){
a1.put(100);
}
}
}
class Fetch implements Runnable
{
int a=2000;
private Account a1;
public Fetch(Account a1)
{this.a1 = a1 ;}
public void run()
{
while(a-->0){
a1.get(100);
}
}
}
public class Test{
public static void main(String[] args){
Account a1 = new Account();
new Thread(new Save(a1)).start();
new Thread(new Fetch(a1)).start();
}
}
put方法的代码块被监视,get函数被监视,保证了value的正确性,输出结果为存钱取钱的随机顺序,因为我这里没有设置存取的制约关系。
package birthday;
class Account
{
int b=0;
void change(int _a) {b=_a;}
int getb() {return b;}
volatile private int value;
synchronized void put(int i)
{
value = value + i;
System.out.println("存入"+i+", 账上金额为:"+value);
}
}
class Save implements Runnable
{
//int a=2000;
private Account a1;
public Save(Account a1)
{
this.a1 = a1;
}
public void run()
{
while(a1.getb()==0) {
try {
Thread.sleep(900);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
a1.put(1);
}
System.out.println("10秒已到,停止存钱。stop!");
}
}
class Fetch implements Runnable
{
//int a=20;
private Account a1;
public Fetch(Account a1)
{this.a1 = a1 ;}
public void run()
{
if(a1.getb()==0) {
try {
Thread.sleep(9000);
} catch (InterruptedException e) {}
}
a1.change(1);
}
}
public class Test{
public static void main(String[] args){
Account a1 = new Account();
new Thread(new Save(a1)).start();
new Thread(new Fetch(a1)).start();
}
}
结果:
存入1, 账上金额为:1
存入1, 账上金额为:2
存入1, 账上金额为:3
存入1, 账上金额为:4
存入1, 账上金额为:5
存入1, 账上金额为:6
存入1, 账上金额为:7
存入1, 账上金额为:8
存入1, 账上金额为:9
存入1, 账上金额为:10
10秒已到,停止存钱。stop!
注:这个题很恶心,线程要想直接停止是没有对应的方法的,线程安全退出的方法就是抛出异常,我这里没有写抛出异常(太难看),也就是说我的程序10秒到了以后没有停止,只是没有输出了,我只能做到这点了
方法:线程1先睡眠10秒,期间线程0运行,10秒后线程1改变标志位,线程0一直在检查标志位,一旦发现改变,就停止输出。
class Account
{
volatile private int value;
synchronized void put(int i)
{
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
value = value + i;
System.out.println(Thread.currentThread().getName()+" 生产者--存入了 "+i+" 余量为:"+value);
}
synchronized int get(int i)
{
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
if (value>i)
value = value - i;
else
{ i = value;
value = 0;
}
System.out.println(Thread.currentThread().getName()+ " 消费者--消费了 "+i+" 余量为:"+value);
return i;
}
}
class Save implements Runnable
{
private Account a1;
public Save(Account a1)
{
this.a1 = a1;
}
public void run()
{
while(true){
a1.put(1);
}
}
}
class Fetch implements Runnable
{
private Account a1;
public Fetch(Account a1)
{this.a1 = a1 ;}
public void run()
{
while(true){
a1.get(1);
}
}
}
public class Test{
public static void main(String[] args){
Account a1 = new Account();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
//10个生产者和消费者
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
}
}
注:我没有设置生产者和消费者之间的关系,所以存在连续生产和连续消费,具有随机性