黑马程序员__java基础__多线程

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
多线程的描述
一.进程、线程
(1)进程:一个正在执行的程序每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
(2)线程:进程中一个负责程序的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。
二.多线程
(1)多线程:java虚拟机启动的时候会有一个java.exe的执行程序,也就是一个进程。该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。JVM启动除了执行一个主线,还有负责垃圾回收机制的线程。像种在一个进程中有多个线程执行的方式,就叫做多线
(2)多线程的好处:解决了多部分代码同时运行的问题提高程序执行效率。
多线程的创建
一.继承方式(继承Thread)
(1)步骤:1. 定义一个类继承Thread类。
                  2. 覆盖Thread类中的run方法。
                  3. 直接创建Thread的子类对象创建线程。
                  4. 调用start方法开启线程并调用线程的任务run方法执行。

(2)分析:1. Thread类中的run方法,用于存储线程要运行的代码,所以自定义线程就必须复写run方法。
                  2.如果线程直接调用run方法,等同于只有一个线程(main)在执行。所以必须要调用start方法才能启动线程。
(3)例
/**
 * 创建两个线程,并输出结果
 * @author Administrator
 */
class Test extends Thread//继承thread类
{
	String name;
	Test(String name)
	{
		this.name=name;
	}
	public void run()//复写run方法
	{
		for(int x=0;x<60;x++)
		{
			System.out.println(name+"x="+x);
		}
	}
}
public class ThreadTest {

	public static void main(String[] args) 
	{
		Test t1=new Test("线程1---");//创建线程
		Test t2=new Test("线程2------");
		t1.start();//启动线程
		t2.start();
		for(int x=0;x<60;x++)//main线程
		{
			System.out.println("main线程-"+"x="+x);
		}			
	}
}
输出结果为:


通过结果可看出:执行是随机、交替执行的。
二.实现方式(实现Runnable)
(1)步骤: 1. 定义类实现Runnable接口。
                   2. 覆盖接口中的run方法,将线程的任务代码封装到run方法中。
                   3. 通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
                   4. 调用线程对象的start方法开启线程。
(2)分析: 1. 为什么要将Runnable接口的子类对象传递给Thread的构造函数?因为线程的任务都封装在Runnable接口子类对象                         的run方法中。 所以要在线程对象创建时就必须明确要运行的任务。
                   2. 实现的方式避免了Java单继承的局限性。所以,创建线程时用实现的方式较为常见。
(3)例
/**
 * 创建两个线程,并输出结果
 * @author Administrator
 */
class Test implements Runnable//实现Runnable接口
{
	public void run()//复写run方法
	{
		for(int x=0;x<60;x++)
		{
			System.out.println(Thread.currentThread().getName() + "-----" + x);
		}
	}
}
public class ThreadTest {

	public static void main(String[] args) 
	{
		Test t=new Test();//创建Runnable子类对象
		Thread d1=new Thread(t);//创建线程并把Runnable子类对象作为实际参数传给Thread的构造函数
		Thread d2=new Thread(t);
		d1.start();//启动线程
		d2.start();
		for(int x=0;x<60;x++)//main线程
		{
			System.out.println("main线程-"+"x="+x);
		}			
	}
输出结果为:


线程的安全问题
一.安全问题出现的原因
(1)多个线程在操作共享的数据。
(2)操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
二.解决办法——同步
(1)同步代码块:格式  synchronized(对象){ 需要被同步的代码;}。其中的对象可以new一个Object对象传进去。
(2)同步函数:格式:在函数上加上synchronized修饰符即可。
(3)同步的前提:1.必须要有两个或者两个以上的线程。2.必须是多个线程使用同一个锁。
(4)同步的利弊:利:解决了多线程的安全问题。弊:多个线程需要判断锁,较为消耗资源。
(5)同步要注意的问题:1.明确哪些代码是多线程运行代码。
                                     2.明确共享数据。
                                     3. 明确多线程运行代码中哪些语句是操作共享数据的。
(6)多线程下的单例模式:
class Single
{
	private static Single s = null;
    private Single(){} 
    public static Single getInstance()
    {
    	if(s ==null)
    	{
    		synchronized(Single.class)
    		{
    			if(s == null)
    				s = new Single();
            }
         }
    	return s ;
    }
}
死锁
一.死锁的出现
当同步中嵌套同步时,就有可能出现死锁现象。
二.死锁示例
/**
写一个死锁程序
*/
class LockTest implements Runnable//定义一个类来实现Runnable,并复写run方法
{
	static Object locka = new Object();
    static Object lockb = new Object();
	private boolean flag;
	LockTest(boolean flag)
	{
		this.flag=flag;
	}
	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(locka)//a锁
				{
					System.out.println("------if_locka");
					synchronized(lockb)//b锁
					{
					System.out.println("------if_lockb");
					}
				}
			}
		}
		else
		{
			while(true)
			{
				synchronized(lockb)//b锁
				{
				  System.out.println("------else_lockb");
					synchronized(locka)//a锁
					{
				   System.out.println("------else_locka");
					}
				}
			}
		}
	}
}
public class DeadLock 
{
	public static void main(String[] args) 
	{
		new Thread(new LockTest(true)).start();
		new Thread(new LockTest(false)).start();
	}
}
线程间通信
一.多个线程在处理统一资源,但是任务却不同,这时候就需要线程间通信。
二.等待/唤醒机制涉及的方法:
(1) wait():让线程处于冻结状态,被wait的线程会被存储到线程池中。
(2) notify():唤醒线程池中的一个线程(任何一个都有可能)。
(3) notifyAll():唤醒线程池中的所有线程。

三.wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中
(1) 这些方法存在与同步中。

(2)使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。

(3)锁可以是任意对象,所以任意对象调用的方法一定定义object类中。

四.wait(),sleep()有什么区别

(1) wait:释放执行权,释放锁。
(2) sleep:释放执行权,不释放锁。
线程的停止
一.run方法结束
(1) 开启多线程运行,运行代码通常是循环结构。只要控制住循环,就可以让 run 方法结束,也就是线程结束。
(2)run方法中有如下代码,设置一个flag标记
public  void run()  
{  
    while(flag)  
    {     
        System.out.println(Thread.currentThread().getName()+"....run");  
    }  
}  
二.线程处于冻结状态
(1)线程处于了冻结状态,无法读取标记。
(2)Thread类提供该方法interrupt()强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
(3)例子:
class StopThread implements Runnable
{
	private boolean flag =true;
	public  void run()
	{
		while(flag)
		{
			System.out.println(Thread.currentThread().getName()+"....run");
		}
	}
	public void changeFlag()
	{
		flag = false;
	}
}
class  StopThreadDemo
{
	public static void main(String[] args) 
	{
		StopThread st = new StopThread();
        <span style="white-space:pre">	</span>Thread t1 = new Thread(st);
        <span style="white-space:pre">	</span>Thread t2 = new Thread(st);	
       <span style="white-space:pre">		</span>t1.start();
        <span style="white-space:pre">	</span>t2.start();	
		int num = 0;
		while(true)
		{
			if(num++ == 60)
			{
				t1.interrupt();//清除冻结状态
				t2.interrupt();
				st.changeFlag();//改变循环标记
				break;
			}
			System.out.println(Thread.currentThread().getName()+"......."+num);
		}
		System.out.println("over");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值