线程的学习笔记

线程的概念:线程是一个程序里面不同的执行路径,(一个进程里面有个主线程,叫main方法),在同一个时间点上,一个CPU只能支持一个线程在执行,java的线程是通过java.lang.thread来实现的

1:可以通过创建Thread的实例来创建新的线程

2:每个线程都是通过特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体,通过调用Thread类的start()方法来启动一个线程

进程的概念:进程是一个静态的概念

两种方式来创建新的线程

第一种:定义线程类实现Runnable接口

Thread myThread = new Thread(target);//target为Runnable接口类型

Runable中只有一个方法:public void run();用于定义线程运行体

使用Runnable接口可以为多个线程提供共享的数据

在实现Runnable接口的类的run方法定义中可以使用Thread的静态方法  public static Thread currentThread() 获取当前线程的引用

 第二种

可以定义一个Thread的子类并重写其run()方法,如

class MyThread extends Thread{

public void run(){}

}

然后生成该类的对象:MyThread myThread = new MyThread()

第一种创建线程的方式

//第一种创建线程的方式,实现Runnable接口,将实现了Runable接口的对象作为参数放到Thread线程中去,调用thread的start方法
public class TestThread1
{
	public static void main(String[] args){
		Runnable1 run1 = new Runnable1();
		//run1.run();//若这样调用,相当于方法的调用,线程仍然只有一个main线程,先把Runnable1线程执行完之后然后再执行main方法中的线程
		Thread thread1 = new Thread(run1);
		thread1.start();//必须要调用thread中的start方法,相当于通知CPU。该线程已经准备就绪,当有时间时候请给与执行
		for(int i = 0;i<100;i++){
		System.out.println("main: "+i);
		}

	}
}
class Runnable1 implements Runnable
{
	public void run(){
		for(int i =0;i<100;i++){
			System.out.println("Runnable1: "+i);
		}
	}
}

该程序中若是调用run1.run();程序的执行过程如下

若是调用Thread的start()方法,执行效果如下图

第二种创建线程的方式:

//第二种创建线程的方式,继承Thread类,直接调用该实现了Thread类的start()方法创建一个线程
public class TestThread2
{
	public static void main(String[] args){
		Runnable1 run1 = new Runnable1();
	    run1.start();
		for(int i = 0;i<100;i++){
		System.out.println("main: "+i);
		}

	}
}
class Runnable1 extends Thread
{
	public void run(){
		for(int i =0;i<100;i++){
			System.out.println("Runnable1: "+i);
		}
	}
}

最好是采用第一种的实现接口的方式来创建线程,因为第一种方式比较灵活,可以继承某一个类,然后又可以实现其他的类,而第二种方式就只能是继承某一个类,一般都用第一种创建线程的方式





import java.util.*;
public class TestInterrupt
{
	public static void main(String[] args){
		MyThread thread = new MyThread();
		thread.start();
		try
		{
			Thread.sleep(10000);//这里的Thread是调用main主线程的Thread
		}
		catch (InterruptedException e)
		{
		}
		thread.interrupt();//当过了10秒之后对打断该线程
	}
}
class MyThread extends Thread //在这里只能用第二种创建线程的方式,因为第一种实现runnable接口的方式并没有sleep方法,只有Thread类才有sleep方法
{
	public void run(){
		while (true)
		{
			System.out.println("---"+new Date()+"---");
			try
			{
				sleep(1000);
			}
			catch (InterruptedException e) //该异常必须捕获,不能从run方法中抛出,因为run方法是继承父类的方法,子类不能抛出父类为抛出的方法
			{
				return;
			}
		}
	}
}


测试join()方法,join方法也是会抛出异常的,所以将异常进行捕获

//测试线程的join方法
public class TestJoin
{
	public static void main(String[] args){
		Thread2 myThread = new Thread2("abl");
		myThread.start();
		try
		{
		myThread.join();	//join()方法是相当于调用run方法,将方法合并到main线程中来,不是两个线程在跑
		}
		catch (InterruptedException e)
		{
			return ;
		}
		
		for(int i = 0;i<10;i++){
		System.out.println("i am Thread");
		}
	}
}
class Thread2 extends Thread
{
	Thread2(String s){
		super(s);
	}
	public void run(){
	 for(int i =0 ;i<10;i++){
		 System.out.println("i am "+getName());
		 try
		 {
			sleep(1000);
		 }
		 catch (InterruptedException e)
		 {
			 return ;
		 }
	 }

	}
}

其中join方法的执行路线图如下所示:


测试yeild方法,执行该方法会让其他的线程先执行

//测试yield()方法,该方法的作用是暂停当前正在执行的线程对象,并执行其他线程
public class TestYeild
{
	public static void main(String[] args){
			Thread3 t1 = new Thread3("t1");//同一个线程类是可以new多个线程对象的
			Thread3 t2 = new Thread3("t2");
			t1.start();
			t2.start();

	}
}
class Thread3 extends Thread
{
	Thread3(String s){
		super(s);
	}
	public void run(){
		for(int i=0;i<100;i++){
            System.out.println("i name"+ i+ getName());
			if(i%10==0){
				yield();
			}
		}
	}
}

测试线程的优先级


线程优先级的代码

//测试线程的优先级
public class TestPriority
{
	public static void main(String[] args){
		Thread t = new Thread(new Thread1());
		Thread t3= new Thread(new Thread2());
		t.setPriority(Thread.NORM_PRIORITY+3);
		t.start();
		t3.start();
	}
}
class Thread1 implements Runnable
{
	public void run(){
		for(int i = 0;i<100;i++){
			System.out.println("thread1 : "+i);
		}
	}
}
class Thread2 implements Runnable
{
	public void run(){
		for(int i =0;i<100;i++){
			System.out.println("thread2: "+i);
		}
	}
}

正确的停止线程的方式:

//正确的停止线程的方式,最好不用stop方法,太简单粗暴,线程来不及关闭一个窗口就直接stop
public class StopThread
{
	public static void main(String[] args){
		RunTest r = new RunTest();
		Thread t = new Thread(r);
		t.start();
		for(int i =0;i<100;i++){
			System.out.println("----"+i);
		}
		r.shutDown();
	}
}
class RunTest implements Runnable
{
	boolean flag = true;
	public void run(){
		while(flag){
			for(int i =0;i<100;i++){
				System.out.println(i);
			}
		}
	}
	public void shutDown(){
		flag = false;
	}
}

线程互斥同步方式:

若想避免多个线程同时访问一个资源,就使用synchronized关键字来对对象进行锁定,不让其他的线程访问,直到该线程访问结束

//测试线程同步
public class TestSync implements Runnable
{
	TestTimer timer = new TestTimer();
	public static void main(String[] args){
		TestSync t = new TestSync();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();

	}
	public void run(){
		timer.add(Thread.currentThread().getName());
	}

}
class TestTimer
{
	private static int num = 0;
	public /*synchronized*/ void add(String name){//也可以在方法前加上关键字synchronized来对该对象进行锁定
		synchronized(this){  //通过synchronized关键字锁定当前对象,这样该代码资源会被锁定,在执行的过程中不被其他的线程所干扰
		num++;
		try
		{
			Thread.sleep(1);
		}
		catch (InterruptedException e)
		{
		}
		System.out.println(name+"是第"+num+"个人访问的");
		}

	}
}





线程死锁的代码:(有问题)

//测试线程死锁的例子
public class TestDeadLine implements Runnable
{
	int flag =1;
	Object o1 = new Object();
	Object o2 = new Object();
	public void run(){
		System.out.println("flag:"+flag);
		if(flag == 1){
			synchronized(o1){
				try
				{
					Thread.sleep(500);
				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			synchronized(o2){
				System.out.println(0);
			}
			}
		}
		if(flag == 0){
			synchronized(o2){
				try
				{
					Thread.sleep(500);
				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			
			synchronized(o1){
				System.out.println(1);
			}
			}
		}
		

	}
	public static void main(String[] args){
		TestDeadLine tdl1= new TestDeadLine();
		TestDeadLine tdl2 = new TestDeadLine();
		tdl1.flag=1;
		tdl2.flag=0;
		Thread t = new Thread(tdl1);
		Thread t2 = new Thread(tdl2);
		t.start();
		t2.start();
	}


}

加锁例子:

//面试题:当m1在执行的时候,m2能够被执行吗   :结果是能够执行m2方法,,原因是因为m1方法使用了加锁,当前的对象不能访问m1方法,但是可以允许其他的对象访问没有加锁的代码段
public class TT implements Runnable
{
	int b =100;
	public synchronized void m1()throws Exception{
		b=1000;
		Thread.sleep(500);
		System.out.println("b="+b);
	}
	public void m2(){
		System.out.println(b);
	}
	public void run(){
		try
		{
			m1();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	public static void main(String[] args){
		TT tt= new TT();
		Thread t = new Thread(tt);
		t.start();
		Thread.sleep(1000);
		tt.m2();//若输出结果b是100的话则在m1()执行的过程中是不能执行m2方法的,
		//因为m1方法中将b修改为1000,但是m1还没有解锁,所以m2只能看到100;
	}
}

生产者和消费者经典问题的代码

public class ProduceConsumer
{
	public static void main(String[] args){
		SyncStack ss = new SyncStack();
		Producer p = new Producer(ss);
		Consumer c = new Consumer(ss);
		new Thread(p).start();
		new Thread(c).start();
	}

}

class WoTou  //定义馒头类
{
	 int id;
	 WoTou(int id){
		 this.id = id;
	 }
	 public String toString(){
		 return "WoTou:"+id;
	 }
}

class SyncStack  //定义装馒头的筐子
{
	int index = 0;
	WoTou[] arrWT =  new WoTou[6];

	public synchronized void push(WoTou wt){
		while(index == arrWT.length){
			try
			{
			this.wait();//让当前正在访问该对象的线程等待(该方法必须是synchronized方法,才能使用wait方法)	
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
		this.notify();//叫醒一个当前对象中等待的线程的方法,一般是和wait配套使用(不是叫醒这个push方法,而是叫醒pop方法)
		arrWT[index] = wt;
		index++;
	}

	public synchronized WoTou pop(){
		while(index ==0){
		  try
			{
			this.wait();//让当前正在访问该对象的线程等待(该方法必须是synchronized方法,才能使用wait方法)	
			}
			catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
		this.notify();//若有多个生产者在生产者,这里就用notifyAll();
		index--;
		return arrWT[index];
	}
}
class Producer implements Runnable
{
	SyncStack ss = null;
	Producer(SyncStack ss){
		this.ss = ss;
	}

	public void run(){
		for (int i =0;i<20 ;i++ )
		{
			WoTou wt =  new WoTou(i);
			ss.push(wt);
			System.out.println("生产了:"+wt);
			try
			{
				Thread.sleep(1000);
			}
			catch (InterruptedException e )
			{
				e.printStackTrace();
			}

		}
	}
}
class Consumer implements Runnable
{
	SyncStack ss = null;
	public Consumer(SyncStack ss){
		this.ss = ss;
	}

	public void run(){
		for (int i=0;i<20 ;i++ )
		{
			WoTou wt =  ss.pop();
			System.out.println("消费了:"+wt);
			try
			{
				Thread.sleep(1000);
			}
			catch (InterruptedException e )
			{
				e.printStackTrace();
			}
			System.out.println(wt);
		}
	}
}
sleep()方法和wait()方法的区别。

第一:sleep()方法是Thread类中的方法,wait()方法是object中的方法

第二:sleep()方法时别的线程不可以访问锁定的对象,wait()方法的时候别的线程可以访问锁定对象,调用wait方法的时候必须要锁定该对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值