JAVA-day09-多线程

/*
多线程:

进程:正在进行中的程序
      也就是在内存中的开辟的一块空间

线程:负责程序执行的一条执行路径
      也可以称为执行单元
	  一个进程至少要有一个线程
	  也就是进程的执行实际上是线程在执行
	  当一个程序中有多个线程的时候,这个程序就是多线程程序

多线程一定能提高效率吗?不一定能提高效率,但是能合理的使用cpu资源
最关键的是能够同时执行同一个程序中的多个功能(多部分代码)


JVM是不是多线程的呢?
至少会有一个线程负责程序的正常执行,执行main方法中的代码----主线程
还得有一个线程负责垃圾回收,执行finalize()方法中的代码---垃圾回收线程

多线程的好处可以实现多个功能的同时执行,或相同的功能同时执行

任务:进程中的每个线程执行的代码
      每个任务代码都有其存储位置
	  比如:主线程的任务代码存储在main方法中
	  垃圾回收线程的代码存储在finalize方法中

	  执行的任务不同,任务代码的存储位置就不同

线程是随着任务的存在而存在
随着任务的执行结束而从内存中消失
*/
class Test
{
	//重写fialize()方法,定义对象被回收的方式,该方法被垃圾回收线程执行
	public void finalize()
	{
	   System.out.println("被回收了");
	}
}
class  Demo1
{
	public static void main(String[] args) //主线程---一个进程至少会有一个主线程
	{
		new Test();
		new Test();
		new Test();
        //每次运行的结果都不一样,这就是多线程的随机性,因为多个线程在抢夺cpu
		System.gc();//运行垃圾回收线程,就是把cpu让给垃圾回收线程

		System.out.println("Hello World!");
	}
}



/*
任金鹏和彭立要同时显示姓名和次数

既然要同时显示,就要用多线程
如何自己创建线程?
第一种方式:
1:定义一个类继承Thread
2:重写run方法
    创建线程是为了执行任务,任务代码需要有存储位置
	run()方法就是这个存储位置
3:创建子类的实例
4:调用start()启动线程

        注意:主线程执行的代码在main方法中
		       自定义线程执行的代码在run方法中

run()和start的区别:
run()方法是一个普通的方法,不具备启动线程的功能,只是一个普通的方法调用
start方法可以启动线程并去执行run()中的任务代码

为什么继承Thread类?
     public static void main(String[] args) 
	 {
         Thread t1 = new Thread();
		 Thread t2 = new Thread();
		 t1.start();
		 t2.start();

        以上这段代码没有执行结果,我们创建线程是为了执行任务,
		任务代码需要有存储位置,run方法就是存储位置
		因为Thread类中的run方法没有实现任何功能,而我们创建的线程的
		任务代码还必须写在run方法中,所以只能是继承Thread类,并
		重写run方法
    }


*/
class Test extends Thread
{
	private String name;
	public Test(String name)
	{
		this.name = name;
	}

	public void run()//定义了任务
	{
		for(int i=1;i<=10;i++)
		{
			//子线程的名字是  Thread-编号  编号从0开始
			System.out.println(Thread.currentThread().getName()+"...show..."+i);
		}
	}
}
class Demo2 
{
	public static void main(String[] args) 
	{
		Test t1 = new Test("任金鹏");//创建了一个线程
		Test t2 = new Test("彭立");//创建了一个线程

        t2.start();//启动线程
        t1.start();//启动线程

		for(int i=1;i<=10;i++)
		{
			//主线程的名字是  main
			System.out.println(Thread.currentThread().getName()+"...show..."+i);
		}

	}
}

 //线程栈中的异常:进程中的某个线程发生异常,只是该线程自己的事儿,不会影响其它线程
 //进程中的所有线程都执行完,进程才会结束
class Test extends Thread
{
	private String name;
	public Test(String name)
	{
		this.name = name;
	}

	public void run()
	{
		int[] arr = new int[2];
		for(int i=1;i<=10;i++)
		{
			System.out.println(arr[2]);
			System.out.println(Thread.currentThread().getName()+"...show..."+i);
		}
	}
}
class Demo3 
{
	public static void main(String[] args) 
	{
		Test t1 = new Test("任金鹏");
		Test t2 = new Test("彭立");
       
        t2.start();
        t1.start();
       // System.out.println(5/0);
	}
}

/*
四个窗口同时卖票
既然是同时卖票,就要用多线程
创建四个线程,每个线程都是卖票
因为都是卖票,所以四个线程执行的任务代码是相同的
只要定义一个类继承Thread类,并重写run方法就o了


为了让四个线程共享100张票,需要把票修饰成static的

实际使用中票不应该修饰为静态的,因为票会有很多种
那怎么解决共享100张票的问题?
创建线程的第二种方式:
1:定义一个类实现Runnable接口
2:重写接口中的run方法
3:创建该子类的实例
4:创建Thread类的实例,实际上就是在创建线程
5:把子类的实例作为参数传递给Thread类的构造方法
          创建线程的目的是 执行任务,而任务代码定义在实现Runnable接口的子类中
		  所以为了让线程执行任务代码,只能是把实现了Runnable接口的子类对象作为参数传递给线程对象
6:启动线程

第二种方式的特点:
1:线程任务和线程对象实现了分离,更加的面向对象
创建好了线程对象,执行什么任务不再重要,只要是实现了Runnable接口的子类对象,就可以作为参数传递给
线程对象,

2:实现接口的同时还可以再继承其它类
*/
class Ticket implements Runnable//这是一个用来描述任务的类
{
	private  int num = 50;

	public void run()
	{
		while(true)
		{
			if(num>0)
			{
				System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
			}
		}
	}
}
class  Demo4
{
	public static void main(String[] args) 
	{
		//Eat  e = new Eat();
		Ticket t = new Ticket();
        Thread t0 = new Thread(e);
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
        t0.start();t1.start();t2.start();t3.start();

		/*
		Ticket t0 = new Ticket();
		Ticket t1 = new Ticket();
		Ticket t2 = new Ticket();
		Ticket t3 = new Ticket();

		t0.start();
		t1.start();
		t2.start();
		t3.start();

		*/
	}
}

/*
为什么创建线程的第二种方式就能解决卖票问题?
      第一种方式创建线程类的同时还得定义任务,任务和线程是绑定在一起的,每创建一个线程都会创建一份儿资源(任务用到的数据)
	  所以,创建四线程就创建了四份资源

	  第二种方式:单独对任务进行描述,只需要创建一个任务对象(只有一份资源),分别让四个线程去执行


为什么Thread类也实现Runnable接口?run方法是提取出的共性的方法
     
第二种方式的关键是,线程任务和线程对象的分离

建议使用第二中方式

*/
class Test implements Runnable//extends Thread
{
	public void run()
	{
	
	}
}
class Demo6
{
	public static void main(String[] args) 
	{
		Test t = new Test();

		Thread d = new Thread(t);
		
	}
}

/*
线程出现了线程安全问题:
     打印了0,-1,-2等错票
线程出现安全问题的原因:
     1:多个线程操作了共享数据
	 2:操作共享数据的语句有多条,当一个线程得到cpu,执行了操作共享数据的多条代码的一部分时,还没执行完,就被其它
	 线程抢走了cpu

	 解决方式:当一个线程在执行操作共享数据的多条代码时,其它线程不能参与执行,只有该线程把所有操作共享数据的代码全部执行完
	 其它线程才能参与执行


	 解决线程安全问题的方式:同步代码块
	 synchronized(对象)//对象是任意的
	 {
	     需要被同步的代码块
	 }
     
	 同步代码块的弊端:不能进入同步代码块的线程要反复的判断锁,降低性能

     
	 使用同步需满足的条件:
        1:至少有两个或两个以上的线程
		2:多个线程使用同一把锁



*/
class Ticket implements Runnable
{
	private  int num = 50;
    private   Object obj = new Object();
	public void run()
	{
		while(true)
		{
			synchronized(obj)
			{
				if(num>0)
				{
					//线程在睡的时候不会释放锁,只是放弃了cpu
					 try{Thread.sleep(10);}catch(InterruptedException e){e.printStackTrace();}
					System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
				}
			}
		}
	}
}
class  Demo6
{
	public static void main(String[] args) 
	{

		Ticket t = new Ticket();
        Thread t0 = new Thread(t);
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);
        t0.start();t1.start();t2.start();t3.start();

		
	}
}

/*
有一个银行,可以存钱
有两个储户同时存钱,每个人存三次,每次存100

*/
class Bank
{
	private int sum =0;
    private Object obj = new Object();
	public synchronized void add(int money)//同步函数
	{
		
			sum = sum +money;
			//---->1   ----->2
			System.out.println("sum="+sum);
		
		
	}
}
//描述任务
class Customer implements Runnable
{
	private Bank bank = new Bank();

	public void run()
	{
		for(int i=1;i<=3;i++)
		{
			bank.add(100);
		}
	}
}
class Demo7 
{
	public static void main(String[] args) 
	{
	     //创建任务对象
		 Customer customer = new Customer();

         Thread t1 = new Thread(customer);
		 Thread t2 = new Thread(customer);

		 t1.start();
		 t2.start();


	}
}

//同步函数的锁?锁是用来实现多个线程之间的互斥,所以同步函数也必须有锁
 //同步函数使用的锁是this
/*
静态同步函数:静态进内存的时候没有使用new创建的对象,但是有其所属的类 的字节码文件对象
             这个对象是 Class类型的对象
			 所以它使用的锁是 其所属的类 的字节码文件对象 类名.class

*/
class Ticket implements Runnable
{
	private  static int num = 50;
    private   Object obj = new Object();
	boolean  flag = true;
	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(Ticket.class)
				{
					if(num>0)
					{
						 try{Thread.sleep(10);}catch(InterruptedException e){e.printStackTrace();}
						System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
					}
				}
			}
		}
        else
		{
			while(true)
				func();
		}
	}
	public static synchronized void func()//锁是Ticket.class
	{
		       if(num>0)
				{
					 try{Thread.sleep(10);}catch(InterruptedException e){e.printStackTrace();}
					System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
				}
	}
}
class  Demo8
{
	public static void main(String[] args) 
	{

		Ticket t = new Ticket();
        Thread t0 = new Thread(t);
		Thread t1 = new Thread(t);
		
        t0.start();
		//让主线程停一会儿,这时候活着的线程只有t0,所以t0一判断flag的值为true,就进入了同步代码块
		try{Thread.sleep(10);}catch(InterruptedException e){e.printStackTrace();}
		//主线程睡醒后把flag的值改为false,当t1线程得到cpu的时候flag的值就是fasle了,从而执行同步函数
		t.flag = false;
 
		t1.start();

		
	}
}


//单例设计模式中懒汉式并发访问的问题
class Single
{
	private static final Single s = new Sigle();
	private Single(){}

	public static Single getInstance()
	{
		return s;
	}
}

class Test implements Runnable
{
	public void run()
	{
		Single2 s = Single2.getInstance();
	}
}
class Single2
{
	private static final Single2 s = null;
	private Single2(){}

	public static Single2 getInstance()
	{
		//从第三个线程开始就不用判断锁了
		if(s==null)
		{
			synchronized(Single2.class)
			{
				if(s==null)
					//--->1   --->2
					s = new Single2();
			}
		}
		return s;
	}
}





class  
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}


//死锁:
class Ticket implements Runnable
{
	private  static int num = 2000;
    private   Object obj = new Object();
	boolean  flag = true;
	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(obj)
				{
					func();
				}
			}
		}
        else
		{
			while(true)
				func();
		}
	}
	public  synchronized void func()
	{
		   synchronized(obj)
		   {
		       if(num>0)
				{
					 try{Thread.sleep(10);}catch(InterruptedException e){e.printStackTrace();}
					System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
				}
		   }
	}
}
class  Demo10
{
	public static void main(String[] args) 
	{

		Ticket t = new Ticket();
        Thread t0 = new Thread(t);
		Thread t1 = new Thread(t);
		
        t0.start();
		//让主线程停一会儿,这时候活着的线程只有t0,所以t0一判断flag的值为true,就进入了同步代码块
		try{Thread.sleep(20);}catch(InterruptedException e){e.printStackTrace();}
		//主线程睡醒后把flag的值改为false,当t1线程得到cpu的时候flag的值就是fasle了,从而执行同步函数
		t.flag = false;
 
		t1.start();

		
	}
}



//线程间的通信: 多个线程执行的任务不同,但是操作的资源相同

//描述资源
class Resource
{
	String name;
	String sex;
}
//定义输入线程执行的任务
class Input implements Runnable
{
	private Resource res;
	private Object obj = new Object();
	public Input(Resource res)
	{
		this.res = res;
	}
	public void run()
	{    
		int i=0;
		while(true)
		{
          synchronized(res)
			{
				if(i==0)
				{
					res.name = "彭立";
					res.sex = "男男";
				}
				else
				{
					res.name = "徐才舒";
					res.sex = "女女女女女女女女女女女";
				}
			}
			i = (i+1)%2;//i不是共享数据
		}
	}
}

//定义输出线程执行的任务
class Output implements Runnable
{
	private Resource res;
	public Output(Resource res)
	{
		this.res = res;
	}
	public void run()
	{
	    while(true)
		{
			synchronized(res)
			{
				System.out.println(res.name+"==="+res.sex);
			}
		}
	}
}
class  Demo11
{
	public static void main(String[] args) 
	{
		//创建资源对象
		Resource res = new Resource();

		//创建输入线程的任务对象
		Input input = new Input(res);

		//创建输出线程的任务对象
		Output output = new Output(res);

		//创建输入线程
		Thread in = new Thread(input);

		//创建输入线程
		Thread out = new Thread(output);

		in.start();
		out.start();


	}
}

/*
一下三个方法必须用在同步中:因为同步中才有锁
wait():等待的线程会释放锁,等待的线程被放入了线程池
notify():唤醒线程池中的任意一个线程
notifyAll():唤醒线程池中的所有线程

为什么wait(),notify(),notifyAll()定义在Object中?
这三个方法都要用锁,而只有同步中才有锁,而同步中的锁是任意的对象
任意对象都能调用的方法只能定义在Object中


*/
class Resource
{
	String name;
	String sex;
	boolean flag = false;
}
//定义输入线程执行的任务
class Input implements Runnable
{
	private Resource res;
	private Object obj = new Object();
	public Input(Resource res)
	{
		this.res = res;
	}
	public void run()
	{    
		int i=0;
		while(true)
		{
          synchronized(res)
			{
			 
                if(res.flag)
					try{res.wait();}catch(InterruptedException e){e.printStackTrace();}//让持有res这个锁的线程去等待
				if(i==0)
				{
					res.name = "彭立";
					res.sex = "男男";
				}
				else
				{
					res.name = "徐才舒";
					res.sex = "女女女女女女女女女女女";
				}
				res.flag = true;
				res.notify();//空唤醒
			}
			i = (i+1)%2;//i不是共享数据
		}
	}
}

//定义输出线程执行的任务
class Output implements Runnable
{
	private Resource res;
	public Output(Resource res)
	{
		this.res = res;
	}
	public void run()
	{
	    while(true)
		{
			synchronized(res)
			{
				if(!res.flag)
					try{res.wait();}catch(InterruptedException e){e.printStackTrace();}
				System.out.println(res.name+"==="+res.sex);
				res.flag = false;
				res.notify();
			}
		}
	}
}
class  Demo12
{
	public static void main(String[] args) 
	{
		//创建资源对象
		Resource res = new Resource();

		//创建输入线程的任务对象
		Input input = new Input(res);

		//创建输出线程的任务对象
		Output output = new Output(res);

		//创建输入线程
		Thread in = new Thread(input);

		//创建输入线程
		Thread out = new Thread(output);

		in.start();
		out.start();


	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值