黑马程序员—线程小结

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! --------------------

一、线程的概念

线程就是进程中的一个独立的单元,线程控制着线程的执行。一个进程中至少是有一个线程的。

线程的一个特性:随机性。因为谁执行都是CPU说的算。

二:如何定义线程

 

(1)继承方式

 第一步:继承Thread

 第二步:重写run方法;这是为了将自定义代码存在run方法中让线程运行

 第三步:调用线程的start方法(启动线程,调用run方法)

(2)实现方式

    第一步:实现Runnable接口

 第二步:覆盖Runnable中的run方法

     第三步:通过Thread类建立线程的对象

   第四步:将Runnable的子类的对象作为参数传给Thread类的构造函数

 第五步:调用Thread start方法,启动线程调用Runnable子类的run方法

1、两种的区别:

Java只支持单继承,也就是说一个类只能继承一个父类,如果此类只需要继承Thread的话那么继承与实现是没有区别的。如果此类还要继承其他类的话这时候就不能使用继承方式了。就只能使用实现Runnable接口的方式。所以实现方式可以避免继承方式的局限性,建议使用实现方式。

2、下面是一个这两种方式的实现以及一些线程的小操作

class Demo1 implements Runnable
{
	public void run()
	{
		for(int y=0;y<10;y++)
		{
			System.out.println(Thread.currentThread().getName()+" y"+y);
			
		}
	}
}
class Demo extends Thread
{
	
	
	public void run()
	{
		for(int i=0;i<10;i++)
		{
			
			
			System.out.println(Thread.currentThread().getName()+" i"+i);//获取当前线程的名称
		}
	}
}
public class Treadtest 
{
	public static void main(String[] args)
	{
		Demo d=new Demo();
		d.start();//启动线程
		Demo1 d1=new Demo1();
		Thread td=new Thread(d1);//建立Thread线程对象,并把对象d1作为参数
		td.start();
		
		for(int i=0;i<10;i++)
		{
			System.out.println("Main run...."+i);
		}
	}
  }

三、多线程的同步

当多线程多条语句都在操作同一共享数据时候,一个线程只对多条语句执行了一部分,另外一个线程参与执行,这样就造成了共享数据的错误。

这样子java就提供了同步的方法来解决这个问题

1、同步的前提:

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

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

2、同步的两种方式

同步代码块

synchronized(对象也就是锁)

{

需要被同步的代码。

}

同步函数:把synchronized 当做修饰符修饰方法

class Ticket2 implements Runnable//1.定义实现Runnable借口的类
{
	static int ticket=100;
	public void run()//2‘覆盖接口中的run方法
	{
		
		while(ticket>0)
		{
				show();
				
					/* synchronized(this)
  同步代码块的方式
					{
						 if(ticket>0)
						 System.out.println(Thread.currentThread().getName()+"........"+ticket--);
					 }*/
		
			}
		}

	public  static synchronized  void show()//同步函数    如果是静态的话,同步方法使用的锁是字节码文件对象
	//也就是ticket.class 如果不是静态的话就是this.
	{
		if(ticket>0)
		{
			System.out.println(Thread.currentThread().getName()+"........"+ticket--);
		
		}
	}
}

public class Threaddingyi
{
	public static void main(String[] args)
	{
		Ticket2 t=new Ticket2();
		new Thread(t).start();//通过Thread类建立线程并将Runnable的子类对象作为参数传递给Thread
		//后调用Thread类中的start方法开启线程,执行Runnable的子类中的run方法
		
		new Thread(t).start();
		new Thread(t).start();
		new Thread(t).start();
		}
}

四、线程间的通信

多线程在操作同一资源,但是操作的方式不一样

class res
{
	private String name;
	private String sex;
	private boolean flag=false;
	public synchronized void set(String name,String sex)
	{
		if(flag)
			try{this.wait();}
		catch(Exception e)
		{
		
		}
		this.name=name;
		this.sex=sex;
		flag=true;
		this.notify();
	}
	public synchronized void prit()
	{
		if(!flag)
			try{this.wait();}
		catch(Exception e){}
		
		System.out.println(name+"....."+sex);
		flag=false;
		this.notify();
		
	}
	
}
class Input implements Runnable
{
	private res r;
	Input(res r)
	{
		this.r=r;
	}
	public void run()
	{
		int x=0;
		while(true)
		{
			if(x==0)
				System.out.println("tt"+"....."+"feman");
			else
				System.out.println("李四"+"....."+"男");
			x=(x+1)%2;
		}
}
	
}
class out implements Runnable
{
	private res r;
	out(res r)
	{
		this.r=r;
	}
	public void run()
	{
		r.prit();
	}
}
 class DengdaiTest 
{
	public static void main(String[] args)
	{
		res r=new res();
		
		Input in=new Input(r);
		out ou=new out(r);
		Thread t=new Thread(in);
		Thread t1=new Thread(ou);
		t1.start();
		t.start();
	}
}

但是此时会出现一个问题,如果同时多个线程操作Input,多个线程操作in的话就会出现问题。如输入两个却只打印一个的情况。所以我们就有了唤醒等待的出现

唤醒等待机制:

1、Wait()notify()要使用在同步中,因为要对持有锁的线程操作

2、我们可以将synchronized替换成Lock操作,将waitnotifynotifyAll替换成condition对象。该对象可以对Lock锁进行获取。这样一个锁可以对应多个condition对象。而第一种的同步只能对应一个wait(),notify()。

操作如下:Lock lock=new ReentrantLock();

Condition con_shengc=lock.newCondition();

下面我们通过一个生产消费者的例子说明

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class shengchang
{
	private String name;
	private boolean flag=false;
	private Lock lock=new ReentrantLock();
	private Condition con_shengc=lock.newCondition();
	private Condition con_xiaofei=lock.newCondition();
	
	public void set(String name) throws InterruptedException 
	{
		lock.lock();
		try{
			while(flag)
		
			con_shengc.await();
	
			this.name=name;
			System.out.println(name+"生产者.....");
			flag=true;
			con_xiaofei.signal();
		}
		
		finally
		{
			lock.unlock();
		}
	}
	public void prit()throws InterruptedException
	{
			lock.lock();
			try{
				while(!flag)//这边如果用if的话会出现多个生产者而只有一个消费者的情况
					con_xiaofei.await();
				System.out.println(name+"消费者...............................");
				
				flag=false;
				con_shengc.signal();
				
			} 
			
			finally {
				lock.unlock();
			}
		
		
	}
}
class produce implements Runnable
{
	private shengchang sc;
	produce(shengchang sc)
	{
		this.sc=sc;;
	}
	public void run() {
		while(true)
		try {
				sc.set("商品");
		} catch (InterruptedException e) {
			
			
		}
		
	}
	
}
class xiaofei implements Runnable
{
	private shengchang sc;
	xiaofei(shengchang sc)
	{
		this.sc=sc;;
	}
	public void run() 
	{
		while(true)
		try {
			sc.prit();
		} catch (InterruptedException e) {
			
		}
	}
}
	
public class ProudceDemo {
	public static void main(String[] args)

	{
		shengchang sc=new shengchang();
		new Thread(new produce(sc)).start();
		new Thread(new produce(sc)).start();
		new Thread(new xiaofei(sc)).start();
		new Thread(new xiaofei(sc)).start();
	}
}

五:停止线程

停止线程就是要使run方法结束。但是当线程都处于冻结状态的时候,那么线程就不会结束。这时我们需要对冻结状态进行清除,强制让线程恢复到运行状态来,这样就可以操作让线程结束。Thread类提供了interrupt方法实现

class stop implements Runnable
{
	private boolean flag=true;
	public synchronized void run() {
		while(flag)
		{
			try{
				wait();
				
			}
			catch(InterruptedException e){
				System.out.println(Thread.currentThread().getName()+"发生异常.....");
				
				flag=false;
			}
	
		}
		 
	}
	
	
}

public class StopThread
{
	public static void main(String[] args) throws InterruptedException  
	{
		stop s=new stop();
		Thread t=new Thread(s);
		Thread t1=new Thread(s);
		t.start();
		t1.start();
		for(int i=0;i<100;i++)
			{
			
				t.interrupt();//使线程一恢复到运行状态,使得t不在处于冻结状态,这样就可以结束线程
				
				t1.interrupt();
				
				System.out.println(i);
			}
		System.out.println("oooo");
	}
}

六:Thread的一些其他方法

1. setDaemon方法:在启动线程之前调用 被setDaemon标识的是后台线程,当前台线程结束后,后台进程自动结束。

2. join方法:A线程执行到了B线程的join方法的时候,A线程等待,等B线程执行完A线程在执行。

3. yield方法:临时停止当前的线程。


------------------------ ASP.Net+Android+IOS开发.Net培训、期待与您交流! ---------------------

-详细请查看:http://edu.csdn.net

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马程序员线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值