黑马程序员08_线程

线程

概述:

  • 1、进程和线程

进程:

是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程。比如在Windows系统中,一个运行的xx.exe就是一个进程。

Java程序的进程里有几个线程:主线程, 垃圾回收线程(后台线程)

线程:

是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程,多个线程可共享数据。

多进程:

操作系统中同时运行的多个程序。

多线程:

在同一个进程中同时运行的多个任务。一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个控制单元。  并发运行。如:多线程下载软件。  可以完成同时运行,但是通过程序运行的结果发现,虽然同时运行,但是每一次结果都不一致。  因为多线程存在一个特性:随机性。  造成的原因:CPU在瞬间不断切换去处理各个线程而导致的。  可以理解成多个线程在抢cpu资源。

扩展:

其实更细节说明jvmjvm启动不止一个线程,还有负责垃圾回收机制的线程。

 

 

知识点一:自定义一个线程


 

  • 方式1:继承Thread类。

步骤:

1、定义类继承Thread

2、复写Thread类中的run方法。

目的:将自定义代码存储在run方法。让线程运行。

3、调用线程的start方法,

该方法两个作用:启动线程,调用run方法。

Thread类用于描述线程。

该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。

也就是说Thread类中的run方法,用于存储线程要运行的代码。

代码如下:

class myThread extends Thread  //1、定义类继承Thread。
	{
		public void run()		//2、复写Thread类中的run方法。
		{
			for(int i=0;i<100;i++)
			{
				System.out.println("thread::::"+i);
			}
		}
	}
class test
{
	public static void main(String[] args) 
	
	{
		myThread mt = new myThread();
		mt.start();       //3、调用线程的start方法,
  //mt.run();				//仅仅是调用run方法,单线程
		for(int i=0;i<100;i++)
		{
			print("main:::"+i);
		}
	}
	public static void print(Object o)
	{
		System.out.println(o);
	}
}
  • 方式2:实现runnable接口

步骤:

1、定义类实现Runnable接口

2、覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。

3、通过Thread类建立线程对象。

4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

为什么要将Runnable接口的子类对象传递给Thread的构造函数。因为,自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。

5、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

代码如:

class myThread implements Runnable
	{
		public void run()//覆盖run()方法
		{
		for(int i=0;i<100;i++)
			{
				System.out.println("mythread::::"+i);
			}
		}
	}

class test
{
	public static void main(String[] args) 
	
	{   //调用:
		myThread mt = new myThread();
		Thread mt1 = new Thread(mt);
		mt1.start();
		for(int i=0;i<100;i++)
		{	
			System.out.println("main::::"+i);
		}
	}
} 

两种方式的区别:

继承Thread:线程代码存放Thread子类run方法中。

实现Runnable线程代码存在接口的子类的run方法。

实现Runnable方式好处:避免了单继承的局限性。在定义线程时,建立使用实现方式。

 

 

知识点二:线程名字


 

class myThread extends Thread
	{	
		public void run()
		{
			for(int i=0;i<100;i++)
			{
				System.out.println(this.getName()+"thread::::"+i);
			}
		}
	}
class test
{
	public static void main(String[] args) 
	
	{
		myThread mt1 = new myThread();
		myThread mt2 = new myThread();
		mt1.start();
		mt2.start();
		for(int i=0;i<100;i++)
		{
			print("main:::"+i);
		}
	}
	public static void print(Object o)
	{
		System.out.println(o);
	}
}
  • 练习:模拟买票系统

错误示例:new出了四个窗口卖了400张票

class myThread implements Runnable
	{	
		private int ticks = 100;
		
		public void run()
		{
		while(ticks>=0)
			{
				System.out.println(Thread.currentThread().getName()+"::::"+ticks--);
			}
		}
	}
class test
{
	public static void main(String[] args) 
	
	{
		myThread m1 = new myThread();
		myThread m2 = new myThread();
		myThread m3 = new myThread();
		myThread m4 = new myThread();
		Thread mt1 = new Thread(m1);
		Thread mt2 = new Thread(m2);
		Thread mt3 = new Thread(m3);
		Thread mt4 = new Thread(m4);
		mt1.start();
		mt2.start();
		mt3.start();
		mt4.start();
	}
}

正确示例:四个窗口用一个对象创建线程,就共同拥有一个ticks,因为是一个对象,就只有一个ticks,也就是说只有100张票

myThread m = new myThread();
		Thread mt1 = new Thread(m);
		Thread mt2 = new Thread(m);
		Thread mt3 = new Thread(m);
		Thread mt4 = new Thread(m);
		mt1.start();
		mt2.start();
		mt3.start();
		mt4.start();

  

 

 

知识点四:同步锁


 

通过分析,发现,打印出0、-1、-2等错票。即多线程的运行出现了安全问题。

问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。

解决办法:

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

同步的前提:

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

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

同步锁的形式:

  • 同步锁形式1即同步代码块,该锁属于对象 e

synchronized(对象e)

{

需要被同步的代码

}

PS当对象相同时,才会是实现同步的效果。对象e可以为其他对象,只要报纸一致就行。

代码示例如下:

class myThread implements Runnable
	{	
		private int ticks = 100;
		Object obj = new Object();
		public void run()
		{
			while(true)
			{
						synchronized(obj)
						{
							if(ticks>0)
							{
							System.out.println(Thread.currentThread().getName()+"::::"+ticks--);
							} 
						}		            
			}
		}
	}
  • 同步锁形式2同步函数。

public synchronized void 方法名()

函数需要被对象调用,那么函数就有一个所属对象引用,就是this,故同步函数使用的是this

代码如下:

public synchronized  void add(int n)

{

sum = sum + n;

try{Thread.sleep(100);}catch(Exception e){}

System.out.println("sum="+sum);

}

  • 同步锁形式3静态函数同步锁。因为静态方法进内存时没有对象,只有该类对应的字节码文件对象,即 类名.class,该对像的类型是class

对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

具体代码如下:

class myThread implements Runnable
	{	
		private int ticks = 100;
		Object o = new Object();
		public void run()
		{
			while(true)
			{
				synchronized(o)//相当于上锁
				{
					if(ticks>0)
					{
						try{Thread.sleep(10);}
						catch(Exception e){}
						System.out.println(Thread.currentThread().getName()+"::::"+ticks--);
					}
				}
			}
		}
	}

 

posted @ 2014-03-11 21:55  让痛苦变成美好的回忆  阅读(129)  评论(0编辑  收藏  举报