JAVASE线程---多线程

线程:通俗的讲就是进程的儿子,进程中包含线程,且最少包含一个线程

  比如说JVM启动的时候有进程java.exe---该进程中至少有一个线程负责java程序的运行

而且这个线程运行的代码存在于main方法----称为主线程


和异常一样,java已经提供了对线程的描述,我们只需要继承Thread或实现Runable接口就可以成为线程

创建线程的步骤:

    继承Thread类或实现Runnable接口

实现好处是避免了单继承的局限性

当一个类是另一个类的子类,但是该类中还必须使用多线程,此时采用实现方式 

    复写run方法

Thread类定义了一个功能

用于存储线程要运行的代码,该存储功能就是run方法

Thread类中的run方法-----也就是线程的存储空间

    Start启动线程


虚拟机定义主线程运行的代码存放在main方法中-----因为程序要从main开始

自定义线程的代码存放位置是覆盖父类的run方法

一个简单的线程例子:

/*
创建两个线程,和主线程交替运行

线程都有自己默认的名称
Thread-编号 该编号从0开始

可以设置线程名称:setName或者构造函数

*/



class Test extends Thread
{
Test(String name)
		{
			super(name);    //父类中已经定义,只需要调用即可
		}
	public void run()
	{
		
		for(int x=0;x<60;x++)
		{
			//System.out.println(this.getName()+"run...."+x);
			System.out.println(Thread.currentThread().getName()+"run...."+x);//与上面相同
		}
	}
	
}

class ThreadTest
{
	public static void main(String[] args)
	{
		Test t1 = new Test("one----");
		Test t2 = new Test("two++++");
		t1.start();
		t2.start();
		
		for(int x=0;x<60;x++)
		{
			System.out.println("main run===="+x);
		}
	}
}

多线程运行中存在的安全问题:

当多个线程操作共享数据时,容易发生多线程安全问题

A线程还没操作完成后,B线程进入操作

因为是在同一个run方法中,容易发生安全问题

场景:单身模式的懒汉式

class Signal
{
	private static  Signal  s =null;
	private Signal(){}
	public static  Signal  getInstance()
	{
		if(s==null)		 
		{
			s=new Signal ();
		}
		return s;
	}
}
/*
    假设两个线程,t1刚进入if语句就挂掉了,
    此时t2进入if语句时,判断s是null,因为t1在还没执行new对象的时候就挂了
    所以造成的结果是两个对象指向的不是同一个
*/

出现安全问题后,可通过同步来进行解决

同步包括同步代码块和同步函数

解决办法是:

    对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行



同步的前提:

    1、必须要有两个或两个以上的线程

    2、必须是多个线程使用同一个锁

    必须保证同步中只能有一个线程-------->保证线程的安全


同步的好处是解决了多线程中的安全问题

但是同时也消耗了资源,每个线程都需要判断锁


同步代码块需要创建锁,持有锁的线程才可以进入同步代码块或同步函数

锁可以是任意类的对象,这里引用Object类的对象

 
Object obj = new Object();
	public  void add(int n)
	{
		synchronized(obj)	//obj是一个锁,监听器,
		{
			sum = sum+n;
			System.out.println("sum= "+sum);
			
		}
}


锁机制相当于:

多个线程(A,B,C)进入以后,假设A线程先抢到执行权

进入锁,此时A持有锁,并将锁的某个状态位改为0,若在A出去之前,A被冻结

失去执行资格,BC也无法进入,因为侦测到状态位为0,即没有获得锁

同步函数:在函数名前面用synchronized修饰

同步函数的锁是this

函数需要被对象调用,那么函数都有一个所属对象引用,就是this

当同步函数被static修饰后,其锁就不再是this

因为静态函数是属于类的,this不可以出现在静态函数中

静态函数进入内存时,内存中没有本类对象,但是一定有该类字节码文件的对象


通过设置flag使两个线程交替执行
class Ticket implements Runnable //extends Thread
{
	private static  int tick = 100;
	Object obj = new Object();  //创建锁
	boolean flag = true ;
	public void run()
	{
		if(flag)
		{
			 
			while(true)
			{
				synchronized(Ticket.class)//静态函数的锁是类名.class,因为静态函数中不牵扯this,若函数不是静态,则须改为this
				{	if(tick>0)
					{ 
						try{Thread.sleep(5);}catch(Exception e){} 
						System.out.println(Thread.currentThread().getName()+"....code"+tick--);
					}
				}
			}
		}else
		{
				while(true)
				show();
		}
		
	}
	public static  synchronized void show()
	{
		if(tick>0)
			{ 
				try{Thread.sleep(5);}catch(Exception e){}//多线程运行出现了错误,不能抛出异常,只能try,因为run是继承的
				System.out.println(Thread.currentThread().getName()+"........show"+tick--);
			}
	
	}
}
class StaticMethodDemo
{
	public static void main(String[] args)
	{
		Ticket t = new Ticket();
		
		Thread t1 = new Thread(t); 
		Thread t2 = new Thread(t); 
		 
		t1.start();
		//利用线程切换,否则主线程有可能在执行时,把三条语句一次性执行完,那flag永远都是false
		//所以需要先让t1执行,然后让主线程睡会,然后在设置false,达到切换的效果
		try{Thread.sleep(10);}catch(Exception e){}
		t.flag=false;
		t2.start();
		 
	}
	
}

程序在某些时刻会发生死锁

当在同步中嵌套同步,但是锁不同,就会发生死锁。

/* 
出现的情况可能是
if中的同步代码块获得a锁后,要b锁
else中的同步代码块获得b锁后,要a锁,
互不相让,就会发生死锁

也可以让两个同步代码块互相包含
*/


class MyLock
{
	static Object locka=new Object();	//创建a锁
	static Object lockb=new Object(); //创建b锁
}

class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag=flag;
	}
	
	public void run()
	{
		if(flag)
		{
			synchronized(MyLock.locka)
			{
			 	System.out.println("if ..locka....");
				synchronized(MyLock.lockb)
				{
					System.out.println("if ...lockb...");
				}
			}
		}
		else
		{
			synchronized(MyLock.lockb)
			{
				System.out.println("else ....lockb..");
				synchronized(MyLock.locka)
				{
					System.out.println("else ....locka..");
				}
			}
			
		}
	}	

}

class DeadLockTest
{
	public static void main(String[] args)
	{
		Thread t1 = new Thread(new Test(true));
		Thread t2 = new Thread(new Test(false));
		t1.start();
		t2.start();
		
	}
}

除此之外,死锁还可能是

Obj锁中包含this锁,This锁中包含Obj

0线程拿着Obj锁,要this锁,1线程拿着this锁,要Obj





 



已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页