java笔记-多线程-线程安全

多线程概述:

/*
** 1.进程:
** 是一个这在执行中的程序,每一个进程执行都有一个顺序,该顺序是一个执行路径,或者叫控制单元。
** 2.线程:
** 就是进程中一个独立的控制单元,线程控制着进程的执行;
** java虚拟机启动时,会有一个进程java.exe.
** 该进程中,至少有一个线程,负责着java程序的执行;
** 3.如何自定义一个线程?
** java中thread类已经提供了对该事物的描述。
** 创建线程的第一种方式:
**     a.定义类继承Thread。
**     b.复写Thread类中的run方法。
**     c.调用线程的start方法:
**           调用该方法有两个作用:启动线程,调用run方法。
** 多线程的运行结果每次都不同:
** 多个线程都获取cpu的执行权,cpu执行到谁,谁就执行
** 在某一个时刻,只能有一个程序在运行(多核除外)
** cpu在进行着快速切换,速度非常快。
** 我们可以形象的把多线程的运行形容为在抢占cpu的执行权。
** 这也是多线程的一个特想:随机性;谁抢到谁执行,至于执行多长时间,cpu说了算。
*/

//定义一个继承自线程Thread的类;
class Demo extends Thread{
	//重写run方法;
	//为什么重写run方法?
	//thread类用于描述线程,该类定义了一个功能,用于存储线程要运
	//行的代码,该存储功能就是run方法;
	//run方法定义线程要运行的代码。
	public void run(){
		//Main线程和Demo线程交替运行如下语句;
		for(int x=0;x<400;x++){
			System.out.println("---Demo Thread Run::"+x);	
		}
	}
}
class ThreadDemo{
	public static void main(String[] args){
		Demo newThread=new Demo();
		//调用start方法,启动线程并执行run方法;
		newThread.start();
		//Main线程和Demo线程交替运行如下语句;
		for(int y=0;y<400;y++){
			System.out.println("+++Main Thread Run!::"+y);
		}
	}
}

若创建对象直接调用run方法,不调研那个start则相当于对象直接调用方法,没有启动线程。程序执行时仍然是main线程,先执行完run方法中的for循环后再执行main中的for循环。

多线程实例:

/*
** 实现两个线程和主程序交替运行。
*/
class Demo extends Thread{
	String name;
	Demo(String name){
		this.name=name;
	}
	public void run(){
		for(int y=0;y<100;y++){
			System.out.println(name+"\tchildren thread run!"+y);
		}
	}
}
class ThreadDemo2{
	public static void main(String[] args){
		Demo d_1=new Demo("-----d_1");	//为便于区分,传递线程标识
		Demo d_2=new Demo("-----d_2");	//为便于区分,传递线程标识
		d_1.start();
		d_2.start();
		for(int x=0;x<100;x++){
			System.out.println("Main thread run!"+x);	
		}
	}
}

线程的四种状态:


获取线程名称:

/*
** 获取线程名称;
** this.getName();
** Thread.currentThread();
*/
class Demo extends Thread{
	String name;
	Demo(String name){
		//this.name=name;
		super(name);	//向父类传递线程名参数,设置线程名;
	}
	public void run(){
		for(int y=0;y<100;y++){
			System.out.println(Thread.currentThread()+"\tchildren thread run!"+y);
			//System.out.println(name+"\tchildren thread run!"+y);
		}
	}
}
class ThreadDemo2{
	public static void main(String[] args){
		Demo d_1=new Demo("-----d_1");	//为便于区分,传递线程标识
		Demo d_2=new Demo("-----d_2");	//为便于区分,传递线程标识
		d_1.start();
		d_2.start();
		for(int x=0;x<100;x++){
			System.out.println(this.getName()+"Main thread run!"+x);	
		}
	}
}
售票实例(线程的第二种实现方式)
/*
** 售票程序.
** 引出实现线程的第二种方法:
** 1.定义类实现Runable接口;
** 2.覆盖Runnable接口中的Run方法;
** 3.通过Thread类建立线程对象;
** 4.将Runnable接口的的对象作为实际参数传递给Thread类的构造函数
**     自定义run方法所属的对象是Runnable接口的子类对象,要让线程
**     去执行指定对象的run方法,就必须明确该run方法所属的对象。
** 5.调用Thread类的start方法,并运行Runnable接口类的Run方法。
*/

/*
** 实现方式和继承方式的区别:
** 实现方式:避免了单继承的局限性;
** 继承Thread:线程代码存放在Thread子类的run方法中。
** 实现Runnable:线程代码存放在Runnable接口的子类的run方法中。
** 在定义线程时,建议使用实现方式;
*/

class Demo implements Runnable{
	private static int tickets=300;
	//将线程要运行的代码放在run方法中。
	public void run(){
		while(true){
			if(tickets>0){
				System.out.println(Thread.currentThread().getName()+"\tsale ticket::"+tickets--);
			}
		}
	}
}
class TicketDemo{
	public static void main(String[] args){
		//创建Runnable接口类的对象;
		Demo d=new Demo();
		//将Runnable接口类的对象作为实际参数传递给Thread线程的构造函数;
		Thread t1=new Thread(d);
		Thread t2=new Thread(d);
		Thread t3=new Thread(d);
		Thread t4=new Thread(d);
		//启动start函数;
		//由于t1~t4的四个线程共用Runnable接口类的run方法。
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

多线程的安全问题:

/*
** 1.Thread.sleep(10)的使用导致共享数据tickets出现错误。
** 当多条语句在操作同一个线程共享数据时,一个线程正在运行该多条语
** 句处理共享数据,但还没有执行完,另一个线程参与进来执行,导致共** 享数据错误。
** 2.解决办法:
** 操作共享数据时,只允许一个线程执行共享数据的操作,在执行过程
** 中,其它线程不得参与。
** 3.java对于多线程的安全问题提供了专业的解决方式。
**    同步代码块 synchronized(对象){需要被同步的代码}
*/
class Demo implements Runnable{
	Object obj=new Object();
	private static int tickets=300;
	//将线程要运行的代码放在run方法中。
	public void run(){
		while(true){
			//同步代码块;
			synchronized(obj){
				if(tickets>0){
					try{
						//sleep函数定义了该函数可能抛出异常;
						//但函数run并未定义抛出异常信息,需手动处理此处可能的异常;
						Thread.sleep(1);
					}
					catch(Exception e){}
					System.out.println(Thread.currentThread().getName()+"\tsale ticket::"+tickets--);
				}
			}
		}
	}
}
class ThreadSafe{
	public static void main(String[] args){
		//创建Runnable接口类的对象;
		Demo d=new Demo();
		//将Runnable接口类的对象作为实际参数传递给Thread线程的构造函数;
		Thread t1=new Thread(d);
		Thread t2=new Thread(d);
		Thread t3=new Thread(d);
		Thread t4=new Thread(d);
		//启动start函数;
		//由于t1~t4的四个线程共用Runnable接口类的run方法。
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

静态同步代码块:

/*
** 1.如何找问题?
**    a.明确哪些代码是多线程运行代码;
**    b.明确共享数据;
**    c.明确多线程运行代码中哪些是操作共享数据的。
**
** 2.同步函数即在函数上声明synchronized,run方法不可声明;
** 3.同步函数用的是哪个锁?
**    函数需要被对象调用,那么函数都有一个所属对象引用,就是this
**    所以同步函数使用的锁是this。
** 4.如果同步函数被静态修饰后,使用的锁是什么?
**    静态进内存,内存中没有本类对象,但是一定有该类对应的字节码文件对象。 类名.class	该对象的类型是class
**    静态同步函数的锁是:该方法所在类的字节码文件对象,即:类名.class 
*/
class Demo implements Runnable{
	Object obj=new Object();
	private static int tickets=300;
	boolean flag=true;
	//将线程要运行的代码放在run方法中。
	public void run(){
		//if else验证了同步代码块和同步函数的锁是否具有同样效果,若效果相同则同步代码块的锁正确,否则异常。
		if(flag){
			while(true){
				//同步代码块;
				//静态同步代码块的锁是该方法所在类的字节码文件对象。
				synchronized(Demo.class){		//此处同步代码块中的参数若为this仍然有异常数值0出现。
					if(tickets>0){
						try{
							//sleep函数定义了该函数可能抛出异常;
							//但函数run并未定义抛出异常信息,需手动处理此处可能的异常;
							Thread.sleep(10);
						}
						catch(Exception e){}
						System.out.println(Thread.currentThread().getName()+"\t-----sale ticket::"+tickets--);
					}
				}
			}
		}
		else{
			while(true){
				show();
			}
		}
	}
	public static synchronized void show(){
		if(tickets>0){
			try{
				//sleep函数定义了该函数可能抛出异常;
				//但函数run并未定义抛出异常信息,需手动处理此处可能的异常;
				Thread.sleep(10);
			}
			catch(Exception e){}
				System.out.println(Thread.currentThread().getName()+"\t+++++sale ticket::"+tickets--);
			}
	}
}
class StaticThread{
	public static void main(String[] args){
		//创建Runnable接口类的对象;
		Demo d=new Demo();
		//将Runnable接口类的对象作为实际参数传递给Thread线程的构造函数;
		Thread t1=new Thread(d);
		Thread t2=new Thread(d);
		//启动start函数;
		//由于t1~t4的四个线程共用Runnable接口类的run方法。
		t1.start();
		try{Thread.sleep(10);}catch(Exception e){}
		d.flag=false;
		t2.start();
	}
}

延迟加载的单例设计模式

//多线程,延迟加载的单例设计模式:
//懒汉式
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;
	}
}

线程死锁

//死锁

//实现自Runnable的类,用于创建多线程。
class Demo implements Runnable{
	boolean flag;
	Demo(boolean flag){
		this.flag=flag;
	}
	//重写Runnable实现中的run方法;
	public void run(){
		System.out.println("Thread");
		//判断两个线程的特定标识;
		if(flag){
			//线程进入锁定对象不同。
			synchronized(objClass.lockA){
				//若线程t1进入,则锁定lockA。
				System.out.println("if lockA.");
				//线程t1执行到此处,执行权若被t2夺走,并且t2锁定了lockB,则发生死锁。
				synchronized(objClass.lockB){
					System.out.println("if lockB.");
				}
			}
		}
		else{
			//线程进入锁定对象不同。
			synchronized(objClass.lockB){
				//若线程t2进入,则锁定lockB。
				System.out.println("else lockB.");
				//线程t2执行到此处,执行权若被t1夺走,并且t1锁定了lockA,则发生死锁。
				synchronized(objClass.lockA){
					System.out.println("else lockA.");
			}	
			}
		}
	}
}
class objClass{
	static Object lockA=new Object(); //创建Object对象。
	static Object lockB=new Object(); //创建Object对象。
}
class DeadLock{
	public static void main(String[] args){
		//Demo d=new Demo();
		//创建线程并传递线程特定标识flag值。
		Thread t1=new Thread(new Demo(true));
		Thread t2=new Thread(new Demo(false));
		//启动线程并执行run方法;
		t1.start();
		t2.start();
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值