黑马程序员-多线程(1)

------- android培训java培训、期待与您交流! ----------

 
 
11.01 概述
 
 

线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。

每个线程都有一个优先级,高优先级线程的执行优先于低优先级线程。每个线程都可以或不可以标记为一个守护程序。当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。

当 Java 虚拟机启动时,通常都会有单个非守护线程(它通常会调用某个指定类的 main 方法)。Java 虚拟机会继续执行线程,直到下列任一情况出现时为止:

  • 调用了 Runtime 类的 exit 方法,并且安全管理器允许退出操作发生。
  • 非守护线程的所有线程都已停止运行,无论是通过从对 run 方法的调用中返回,还是通过抛出一个传播到 run 方法之外的异常。

创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。例如,计算大于某一规定值的质数的线程可以写成:

 


     class PrimeThread extends Thread {
         long minPrime;
         PrimeThread(long minPrime) {
             this.minPrime = minPrime;
         }
 
         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }
 

然后,下列代码会创建并启动一个线程:

 

     PrimeThread p = new PrimeThread(143);
     p.start();
 

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:

 


     class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }
 
         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }
 

然后,下列代码会创建并启动一个线程:

 

     PrimeRun p = new PrimeRun(143);
     new Thread(p).start();
 

每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。

 

 

 
 
/*
进程:是一个正在执行中的程序
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元
 
线程:就是进程中一个独立的控制单元
线程在控制着进程的执行
 
一个进程中至少有一个线程
 
Java Vm 启动的时候就有一个进程java.exe
该进程中至少有一个线程在负责java程序的执行
而且这个线程运行的代码存在于main方法中
 
该线程称之为主线程
扩展:其实jvm,启动的时候不只一个线程,还有负责垃圾回收机制的线程
1。如何在自定义的代码中,自定义一个线程呢?
通过对api(Application Programming Interface, 应用程序编程接口)的查找,java已经提供了对线程这类事物的描述,就是Thread类
 
 
11.02  创建线程-继承Thread类
 
 
创建线程的第一种方式:继承Thread类
步骤;
1,定义类,继承Thread类
2。复写run方法
目的:将自定义的代码存储在run方法中,让线程运行
3,创建一个对象,执行start方法,
该方法有两个作用:启动线程,调用run
 
 
发现运行结果每一次都不同
因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行
明确一点,在某一个时刻,只能有一个程序执行(多核除外)
cpu在做着快速的切换,以达到看上去是同时运行的效果
我们可以形象把多线程的运行形容为在互相抢夺cpu的执行权
 
这就是多线程的一个特性:随机性,谁抢到谁执行,至于执行多长,cpu说的算
这个过程是随机的
 
11.03 run start的特点
 
 
为什么要覆盖run方法呢?
Thread用于描述线程
该类就定义了一个功能(run function),用于存储线程要运行的代码,该功能就是run方法
 
也就是Thread类中的run方法,用于存储线程要运行的代码(主线程存在于main方法中)
*/
 
class Demo extends Thread
{
	public void run()
	{
		for (int x=0;x<60;x++)
			System.out.println("demo run--"+x);
	}
}

class  ThreadDemo
{
	public static void main(String[] args)
	{
		Demo d = new Demo();//创建好了一个线程
		d.start();//开启线程,并调用该线程的run方法
		//d.run();//仅仅是调用了对象方法,线程没有启动,是主线程的动作

		for (int x = 0;x < 60;x++ )
		{
			System.out.println("Hello World!--"+x);
		}
	}
}
 
 
11.04 线程练习
 
第11天-06-多线程(获取线程对象以及名称)
 
/*
线程都有自己的名称,通过getName函数获取
Thread-编号,该编号从0开始
 
static Thread currentThread();获取当前线程对象
 
设置线程名称:setName或者构造函数(super关键字)
*/
 
class Test extends Thread
{
	// private String name;
	Test(String name)
	{
		//this.name = name;//构造函数和成员变量不能在成员方法中,是独立存在的
		super(name);	
	}
	public void run()
	{	
		for (int x= 0;x < 60; x++)
		{
			System.out.println((Thread.currentThread()==this)+"--test--"+x+"--"+this.getName());
		}
		
	}
}

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--" + x);
		}
		
	}
}
 
 
11.05 线程运行状态 
 
 
 

 
 
 
11.07 售票的例子
11.08实现RUNABLE接口
 
 
/*
需求:简单的卖票程序
多个窗口同时卖票
 
程序运行后发现了一个问题:
1.卖票的时候有重复行为,这时考虑将tick设置为静态共享数据
但是静态有其局限性;
2.也可以考虑创建一个线程让他执行四次,但是运行会报告线程异常,一个线程被启动了四次,明显是
一种浪费而且不符合程序设计初衷
3。这时就考虑线程创建的问题了
------------------------------
 
 
线程创建的第二种方式:实现Runnable接口
 
步骤:
1.定义类实现Runnable接口
2,覆盖Runnable接口中的run方法
将线程要运行的代码存在于该run方法中
3,通过Thread类建立线程对象
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
 
5.调用Thread类的strat方法开启线程并调用Runnable接口子类的run方法
------------------------------------
实现方式和继承方式有什么区别吗?
 
继承方式时,只能单继承,想要实现多线程就要创建一个子类对象,子类对象运行的时候会调用run方法,多个对象调用的时候会重复调用run方法中的代码,等于多个人在做一件事情,是一种浪费
 
实现方式时,将Runnable接口的子类创建的对象作为参数传递给Thread的构造函数,这时Thread类创建的对象会运行多个线程,但是执行的代码是同一块代码,等于多个人在一起做一件事情,效率更高也没有浪费
 
-------------------------------------------------------------
实现方式好处:避免了单继承的局限性
在定义线程时,建议使用实现方式
*/
class Ticket implements Runnable
{
	private //static  int tick = 100;
	public void run()
	{
		while (true)
		{
			if (tick > 0)
			System.out.println("sale : "+ tick--);
		}
	}
}

class  TicketDemo
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();/该对象非线程
		Thread t1=new Thread(t);
		Thread t2=new Thread(t);
		Thread t3=new Thread(t);
		Thread t4=new Thread(t);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();//这四个对象此时调用start方法调用的run方法,调用的Ticket类的对象只有一个,就是Runnable类接口的子类所创建的Ticket类对象t
	}
}
 
 
 
 
11.09 多线程的安全的问题
11.10同步代码块
 
/*
通过分析,发现打印出0.-1.-2等错票
 
 
多线程的运行出现了安全问题:
 
问题的原因:
当多条线程在操作同一个共享数据时,一条线程对这个数据只执行了一部分,,还没有执行完
另一个线程参与进来执行,导致共享数据的错误(代码中tick的判断出现了错误)
解决方案:
对多条线程执行操作共享数据时,只能让一个线程都执行完,在执行过程中其他不可以参与执行
 
java中内置了解决方式:
同步代码块
 synchronized(对象)
 {
需要被同步的代码
 }
 
同步的前提;
1。必须要有两个或两个以上的线程
2。必须是多个线程使用同一个锁
 
必须保证同步中只有一个线程在运行
 
好处;解决了多线程的安全问题
弊端:多个线程都需要判断锁,较为消耗资源
*/
 
class Ticket implements Runnable
{
	private int tick = 10000;
	Object obj = new Object();
	public void run()
	{
		while (true)
		{
			synchronized (obj)
			{	
				if (tick > 0)
					try
					{
						Thread.sleep(10);
					}
					catch (Exception e)
					{
						
					}//这个异常不能抛,因为是接口类型
				System.out.println(Thread.currentThread().getName()+"sale : "+ tick--);
			}
		}
	}
}

class  TicketDemo2
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		Thread t1=new Thread(t);
		Thread t2=new Thread(t);
		Thread t3=new Thread(t);
		Thread t4=new Thread(t);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}
 
 
 
11.11 同步函数
 
/*
需求:
银行有一个金库,有两个储户分别存300元,每次存100,存3次
 
目的:该程序是否有安全问题,如果有,如何解决?
 
如何找问题;
1,明确哪些代码是多线程运行代码
2,明确共享数据
3。明确多线程运行代码中哪些语句是操作共享数据的
*/
 
class Bank
{
	private int sum;
	Object obj = new Object();
	public synchronize//或则  void add(int n)
	{
		synchronized(obj)
		{
			sum = sum + n;
			try
			{
				Thread.sleep(10);
			}
			catch (Exception e)
			{
			}//这个函数可以抛出
			System.out.println("sum="+sum);
		}
	}
}

class Cus implements Runnable
{
	private Bank b = new Bank();
	public void run()
	{
		for (int x = 0; x < 3; x++)
		{
			b.add(100);
		}
	}
}


class  BankDemo
{
	public static void main(String[] args) 
	{
		Cus c = new Cus();
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
	}
}
 
11.12 同步函数的锁是this
 
/*
同步函数使用的锁是this
 
 
 
*/
 
 
 
class Ticket implements Runnable
{
	private int tick = 100;
	boolean flag = true;
	public void run()
	{
		if (flag)
		{
			while (true)
			{	
				synchronized(this)
				{
					if(tick > 0)
					{
						try{Thread.sleep(10);}catch (Exception e){}
						System.out.println(Thread.currentThread().getName()+"--code--"+tick--);
					}
				}
			}
        }
		else 
			while (true)
				show();
	}
	public synchronized void show()
	{
		if (tick > 0)
		{
			try{Thread.sleep(10);}catch (Exception e){}
			System.out.println(Thread.currentThread().getName()+"--show--"+tick--);
		}
	}
}

class  ThislockDemo
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		Thread t1=new Thread(t);
		Thread t2=new Thread(t);
		t1.start();
		try{Thread.sleep(10);}catch (Exception e){}
		t.flag = false;
		t2.start();
	}
}
 
 
11.13 静态同步函数的锁是Class对象
 
 
/*
如果同步函数被静态修饰后,使用的锁是什么呢?
通过验证发现不再是this了
 
静态方法中也不会有this
 
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象
类名.class,该对象的类型是Class
 
静态的同步方法使用的锁是该方法所在类的字节码文件对象,类名.class
 
*/
 
 
 
class Ticket implements Runnable
{
	private static int tick = 100;
	//Object obj = new Object();
	boolean flag = true;
	public void run()
	{
		if (flag)
		{
			while (true)
			{	
				synchronized(Ticket.class)
				{
					if(tick > 0)
					{
						try{Thread.sleep(10);}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(10);}catch (Exception e){}
			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();
		try{Thread.sleep(10);}catch (Exception e){}
		t.flag = false;
		t2.start();
	}
}
 
 
 
 
11.14 单例设计模式 懒汉式
 
 
 
class Single//懒汉式
{
	private static Single s = null; 
	private Single(){}

	public static //synchronized Single getInstance()//可以用同步函数或者同步代码块解决多线程访问的安全问题,但是相比较同步代码块效率更高
	{
		if (s==null)//多线程访问时会存在安全问题,需要同步
		{
			synchronized(Single.class)// 什么意思?
			{	if(s==null)
				s = new Single();
				
			}
		}
                retrun s;
	}
}

//饿汉式
class Single
{
	private static final Single s = new Single();
	private Single(){}

	public static  getInstance()
	{
		return s;
	}
}
 
 
 
 
11.15多线程-死锁
 
 
/*
死锁;
同步中嵌套同步
 
 
*/class Ticket implements Runnable
{
	private int tick = 100;
	boolean flag = true;
	Object obj = new Object();
	public void run()
	{
		if (flag)
		{
			while (true)
			{	
				synchronized(obj)
				{
					show();
				}
			}
        }
		else 
			while (true)
				show();
	}
	public synchronized void show()
	{
		synchronized(obj)
				{
					if(tick > 0)
					{
						try{Thread.sleep(10);}catch (Exception e){}
						System.out.println(Thread.currentThread().getName()+"--code--"+tick--);
					}
				}
	}
}

class  DeadLockDemo
{
	public static void main(String[] args) 
	{
		Ticket t = new Ticket();
		Thread t1=new Thread(t);
		Thread t2=new Thread(t);
		t1.start();
		try{Thread.sleep(10);}catch (Exception e){}
		t.flag = false;
		t2.start();
	}
}
 
 
 
 
 
 
 
简单版本:
class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag=flag;
	}
	public void run();
	{
		if(flag)
		{        while(true)
                        {
			synchronized(locka)
			{
				System.out.println("if lcoka ");
				synchronized(lockb)
				{
					System.out.println("if lockb");
				}
			}
                        }
		}
		else()
		{
			synchronized(lockb)
			{
				System.out.println("else lockb");
				synchronized(locka)
				{
					System.out.println("else locka");
				}
			}
		}
	}
}

class MyLock
{
		Object locka=new Object();
		Object lockb=new Object();

}




class  
{
	public static void main(String[] args) 
	{
		Thread t1 = new Thread(new Test(true));
		Thread t2 = new Thread(new Test(false));
		t1.start();
		t2.start();
	}
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值