黑马程序员——Java基础——Object,包和多线程基础(一)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

package cn.fuxi._01Object;
/**
 * Object:所以类的根类.
 * object是不断抽取而来,具备着左右对象都具备的共性内容.
 * 
 * P.S. ==以及Object类的equals方法默认都是根据对象的哈希值判断两个对象是否相等.
 * 可以通过覆盖Object的equals来重写比较规则
 * 
 * Object类的toString方法默认返回的内容时"对象所属的类名+@+对象的哈希值(十六进制)".
 */
class Person{
	private int age;
	Person(int age){
		this.age = age;
	}
	public int hashCode(){
		return age;
	}
}
class Person1{
	private int age;
	Person1(int age){
		this.age=age;
	}
	//比较Person的年龄,是否是同龄人
	//一般都会覆盖此方法,根据对象的特有内容,建立判断对象是否相同的依据.
	public boolean equals(Object obj){
		if(!(obj instanceof Person1)){
			throw new ClassCastException("类型错误");
		}
		Person1 p = (Person1)obj;
		return this.age==p.age;
	}
}
class Demo{}

public class ObjrctDemo1 {

	public static void main(String[] args) {
	/*	Person p1 = new Person(10);
		Person p2 = new Person(20);
		Person p3 = p1;
		Demo d = new Demo();
		System.out.println(p1==p2);//f
		System.out.println(p1.equals(p2));//f
		System.out.println(p1.equals(p3));//t
		System.out.println(p1.equals(d));//f
	*/
		Person1 p1 = new Person1(20);
		Person1 p2 = new Person1(20);
		System.out.println(p1.equals(p2));//t
		System.out.println(p1.toString());
		Person p = new Person(19);
		System.out.println(p);
		System.out.println(p.getClass().getName()+"$"+
Integer.toHexString(p.hashCode()));
		System.out.print(p.getClass().getName());
		System.out.print("@");
		System.out.print(Integer.toHexString(p.hashCode()));
	}

}
运行结果:

true
cn.fuxi._01Object.Person1@75f10df7
cn.fuxi._01Object.Person@13
cn.fuxi._01Object.Person$13
cn.fuxi._01Object.Person@13


包:

package packa;

public class DemoA extends packb.DemoB {
	public void show(){
		method();
		System.out.println("demoa run show");
	} 

}
package packb;

public class DemoB {
	protected void method(){
		System.out.println("demob show run");
	}
}

package cn.fuxi.packagedemo;
/**
 * 包
 * 对类文件进行分类管理.
 * 给类提供多层命名空间.
 * 写在程序文件的第一行.
 * 
 * 类名的全称是:包名.类名.
 * 包也是一种封装形式.
 * P.S. 包与包之间的类进行访问,被访问的宝中的类必须是public的,
 * 被访问的包中的类的方法也必须是public的.
 * 
 * 包之间的访问:被访问的包中的类权限必须是public的.
 * 类中的成员权限:public或者protected.
 * protected是为其他包中的子类提供的一种权限.
 * 
 * 四种权限:
 * 			public	protected	default	private
 * 同一类中		f		f			f		f
 * 同一包中		f		f			f
 * 子类			f		f	
 * 不同包中		f
 * 
 * import
 * 一个程序文件中只有一个package,但可以有多个import.
 */
//import packa.DemoA;导入包中某一类
//import packb.DemoB;
import packa.*;//导入包中所有类

public class PackageDemo {

	public static void main(String[] args) {
		DemoA da = new DemoA();
		da.show();
	}

}
/*
 * 例:
 * 有两个类:DemoA,DemoAbc.
 * 所在文件目录如下:
 * packa\DemoA.class
 * packa\abc\DemoAbc.class
 * 
 * 导包语句如下:
 * import packa.*;
 * import packa.abc.*;
 * 
 * jar包
 * java的压缩包.
 * 方便项目的携带.
 * 方便于使用,只要在classpath设置jar路径即可.
 * 数据库驱动,SSH框架等都是以jar包体现的.
 * 
 * jar包的操作:
 * 通过jar.exe工具对jar的操作.
 * 
 * 创建jar包:
 * jar-cvf mypack.jar packa packb
 * 查看jar包:
 * jar-tvf mypack.jar [>定向文件]
 * 解压缩:
 * jar -xvf mypack.jar
 * 自定义jar包的清单文件
 * jar -cvfm mypack.jar mf.txt packa packb
 */
运行结果:

demob show run
demoa run show

多线程的概念:

package cn.fuxi.duoxiancheng;
/**
 * 多线程
 * 进程 线程 多进程的概念
 * 进程:正在经行中的程序(直译)
 * 线程:进程中一个负责程序执行的控制单元(执行路径).
 * 
 * P.S.
 * 1.一个进程中可以有多个执行路径,称之为多线程.
 * 2.一个进程中至少要有一个线程.
 * 3.开启多个线程是为了同时运行多部分代码,每一个线程都有自己运行的内容,
 * 这个内容可以成为线程要执行的任务.
 * 
 * 多线程的好处:解决了多部分代码同时运行的问题.
 * 多线程的弊端:线程太多,会导致效率的降低.
 * 其实,多个应用程序同时执行都是CPU在做着快速的切换完成的.这个切换是随机的.
 * CPU的切换是需要花时间的,从而导致了效率的降低.
 * 
 * JVM启动时启动了多条线程,至少有两个线程可以分析的出来:
 * 1.执行main函数的线程,该线程的任务代码都定义在main函数中.
 * 2.赋值垃圾回收的线程.
 */
class Demo extends Object{
	public void finalize(){
		System.out.println("demo ok");
	}
}
public class DuoXianChengDemo {
	public static void main(String[] args) {
		new Demo();
		new Demo();
		new Demo();
		System.gc();//表示告诉垃圾回收器调用finalize,把垃圾收走,不一定立即执行
		System.out.println("Hello World!");
	}
}
运行结果:

Hello World!
demo ok
demo ok
demo ok

package cn.fuxi.duoxiancheng;
/**
 * 创建线程方式之一:继承Thread类
 * 1.定义一个类继承Thread类.
 * 2.覆盖Thread类中的run方法.
 * 3.直接创建Thread的子类对象创建线程.
 * 4.调用start方法开启线程并调用线程的任务run方法执行.
 */
/*
 *在单线程程序中,只有上一句代码执行完,下一句代码才有执行机会.
 *创建线程的目的就是为了开启一条执行路径,去运行指定的代码和其他代码实现同时运行,而运行的指定代码
 *就是这个执行路径的任务.
 *
 *jvm创建的主线程的任务都定义在了主函数中.而自定义的线程,它的任务在哪儿呢?
 *Thread类用于描述线程,线程是需要任务的.所以Thread类也有对任务的描述.这个任务就是通过Thread类
 *中的run方法来体现.也就是说,run方法就是封装自定义线程运行任务的函数,run方法中定义的就是线程要运
 *行的任务代码.
 *
 *开启线程是为了运行指定代码,所以只有继承Thread类,并复写run方法,将运行的代码定义在run方法中即可.
 * 
 */
//单线程示例
class Demo1{
	private String name;
	Demo1(String name){
		this.name = name;
	}
	public void show(){
		for(int x = 0;x<10;x++){
			System.out.println(name + "..x="+x);
		}
	}
}
class Demo2 extends Thread{
	private String name;
	Demo2(String name){
		this.name = name;
	}
	public void run(){
		for(int x = 0;x<10;x++){
			System.out.println(name + "...x= " + x +
"...ThreadName= "+Thread.currentThread().getName());
		}
	}
}
public class ThreadDemo {
	public static void main(String[] args) {
	/*	Demo1 d1 = new Demo1("小白");
		Demo1 d2 = new Demo1("小强");
		d1.show();//单线程
		d2.show();
	*/
		Demo2 d1 = new Demo2("旺财");
		Demo2 d2 = new Demo2("强哥");
		d1.start();
		d2.start();
		for(int x = 0; x<10; x++){
			System.out.println("x = " +x+"...over..."+
Thread.currentThread().getName());
		}
	}
}
/*
 *1.可以通过Thread的getName()方法获取线程的名称,名称格式:Thread-编号(从0开始).
 *2.Thread在创建的时候该Thread就已经命名到了.
 */
运行结果:

x = 0...over...main
x = 1...over...main
x = 2...over...main
旺财...x= 0...ThreadName= Thread-0
强哥...x= 0...ThreadName= Thread-1
旺财...x= 1...ThreadName= Thread-0
x = 3...over...main
旺财...x= 2...ThreadName= Thread-0
强哥...x= 1...ThreadName= Thread-1
旺财...x= 3...ThreadName= Thread-0
x = 4...over...main
旺财...x= 4...ThreadName= Thread-0
强哥...x= 2...ThreadName= Thread-1
旺财...x= 5...ThreadName= Thread-0
x = 5...over...main
旺财...x= 6...ThreadName= Thread-0
强哥...x= 3...ThreadName= Thread-1
旺财...x= 7...ThreadName= Thread-0
x = 6...over...main
旺财...x= 8...ThreadName= Thread-0
强哥...x= 4...ThreadName= Thread-1
旺财...x= 9...ThreadName= Thread-0
x = 7...over...main
x = 8...over...main
x = 9...over...main
强哥...x= 5...ThreadName= Thread-1
强哥...x= 6...ThreadName= Thread-1
强哥...x= 7...ThreadName= Thread-1
强哥...x= 8...ThreadName= Thread-1
强哥...x= 9...ThreadName= Thread-1

package cn.fuxi.duoxiancheng;
/**
 * 创建线程方式二:实现Runnable接口
 * 1.定义类实现Runnable接口.
 * 2.覆盖接口中的run方法,将线程的任务代码封装到run方法中.
 * 3.通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数
 * 的参数经行传递.为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中.所以
 * 要在线程对象创建时就必须明确要运行的任务.
 * 4.调用线程对象的start方法开启线程.
 * 
 * 实现Runnable接口的好处:
 * 1.将线程的任务从线程的子类中分离出来.经行了单独的封装,安装面向对象的思想将任务封装成
 * 对象.
 * 2.避免了java单继承的局限性.所以,创建线程的第二种方式较为常用.
 */
//准备拓展Demo类的功能,让其中的内容可以作为线程的任务执行.
//通过接口的形式完成.
class Demo3 implements Runnable{
	public void run(){
		show();
	}
	public void show(){
		for (int i = 0; i < 20; i++) {
			System.out.println(Thread.currentThread().getName()+"..."+i);
		}
	}
}

public class ThreadDemo2 {
	public static void main(String[] args) {
		Demo3 d = new Demo3();
		Thread t1 = new Thread(d);
		Thread t2 = new Thread(d);
		t1.start();
		t2.start();
	}
}
运行结果:

Thread-1...0
Thread-0...0
Thread-1...1
Thread-0...1
Thread-1...2
Thread-0...2
Thread-1...3
Thread-0...3
Thread-1...4
Thread-0...4
Thread-1...5
Thread-0...5
Thread-1...6
Thread-0...6
Thread-1...7
Thread-0...7
Thread-1...8
Thread-0...8
Thread-1...9
Thread-0...9
Thread-1...10
Thread-0...10
Thread-1...11
Thread-0...11
Thread-1...12
Thread-0...12
Thread-1...13
Thread-0...13
Thread-1...14
Thread-0...14
Thread-1...15
Thread-0...15
Thread-1...16
Thread-0...16
Thread-1...17
Thread-0...17
Thread-1...18
Thread-0...18
Thread-1...19
Thread-0...19

package cn.fuxi.duoxiancheng;
/**
 * Thread类 Runnable接口内部源码关系模拟代码:
 */
class Thread1{
	private Runnable r;
	Thread1(){}
	Thread1(Runnable r){
		this.r = r;
	}
	public void run(){
		if(r!=null){
			r.run();
		}
	}
	public void start(){
		run();
	}
}
class ThreadImpl implements Runnable{
	public void run(){
		System.out.println("runnable run");
	}
}
class SubThread extends Thread1{
	public void run(){
		System.out.println("hahaha");
	}
}
public class ThreadDemo3 {
	public static void main(String[] args) {
		ThreadImpl i = new ThreadImpl();
		Thread1 t = new Thread1(i);
		t.start();
		SubThread st = new SubThread();
		st.start();
	}
}
运行结果:

runnable run
hahaha

模拟卖票:

package cn.fuxi.duoxiancheng;
/**
 * 线程安全问题:
 * 模拟4个线程同时卖100张票.
 */
class Ticket implements Runnable{
	private int num = 100;
	public void run(){
		while(true){
			if(num>0){
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"...sale..."+ num--);
			}
		}
	}
}

public class ThreadDemo4 {

	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();
		//会售出重复的,还有负数的票
	}
}
/*
 *原因分析:
 *出现上述安全问题的原因在于thread-0通过了if判断后,在执行到"num--"语句之前,num此时仍等于1.
 *CPU切换到Thread-1 Thread-2 Thread-3 之后,这些线程依然可以通过if判断,从而执行"num--"的
 *操作,因而出现了0 -1 -2的情况.
 */
运行结果:

Thread-0...sale...8
Thread-3...sale...7
Thread-1...sale...6
Thread-2...sale...4
Thread-0...sale...5
Thread-3...sale...6
Thread-0...sale...3
Thread-2...sale...2
Thread-3...sale...2
Thread-1...sale...3
Thread-0...sale...1
Thread-1...sale...-1
Thread-3...sale...0
Thread-2...sale...1

package cn.fuxi.duoxiancheng;
/**
 * 线程安全问题产生的原因:
 * 1.多个线程在操作共享的数据.
 * 2.操作共享数据的线程代码有多条.
 * 当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生.
 * 
 * 线程安全问题的解决方案
 * 思路:
 * 就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算.
 * 必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算.
 * 
 * 在java中,用同步代码块就可以解决这个问题.
 * 同步代码块的格式:
 * synchronized(对象){
 * 		需要被同步的代码;
 * }
 * 
 * 同步的好处:解决了线程的安全问题.
 * 同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率.
 * 同步的前提:必须有多个线程并使用同一个锁.
 */
class Ticket2 implements Runnable{
	private int num = 100;
	Object obj = new Object();
	public void run(){
		while(true){
			synchronized(obj){
				if(num>0){
					System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
				}
			}
		}
	}
}

public class ThreadDemo5 {
	public static void main(String[] args) {
		Ticket2 t = new Ticket2();
		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();
	}
}
/*
 * 原因分析:
 * 上图显示安全问题已被解决,原因在于Object对象相当于是一把锁,只有抢到锁的线程,才能进入同步代码块向下执行.
 * 因此,当num=1时,CPU切换到某个线程后,如上面的Thread-3线程,其他线程无法通过同步代码块进行if判断语句,只
 * 有等到Thread-3线程执行完"num--"的操作(此后的值为0),并跳出同步代码块后,才能抢到锁.其他线程即使抢到锁,
 * 然而,此时num值已经为0,也就无法通过if语句判断,从而无法再执行"num--"的操作了,也就不会出现0,-1,-2的情况
 * 了.
 */
运行结果:

Thread-1...sale...10
Thread-1...sale...9
Thread-1...sale...8
Thread-1...sale...7
Thread-1...sale...6
Thread-1...sale...5
Thread-1...sale...4
Thread-1...sale...3
Thread-1...sale...2
Thread-1...sale...1

同步代码块:

package cn.fuxi.duoxiancheng;
/**
 * 利用同步代码块解决安全问题
 * 需求:储户,两个,每个都到银行存钱,每次存100,共三次.
 * 安全问题的第一种解决方案:同步代码块;
 * 安全问题的第二种解决方案:同步函数.
 * 
 * 同步函数和同步代码块的区别:
 * 1.同步函数的锁固定是this
 * 2.同步代码块的锁是任意的对象.
 * 建议使用同步代码块.
 */
//同步代码块
class Bank{
	private int sum;
	public void add(int num){
		synchronized(this){
			sum = sum +num;
			System.out.println("sum = "+sum);
		}
	}
}
//同步函数
class Bank2{
	private int sum;
	public synchronized void add(int num){
		sum = sum +num;
		System.out.println("sum = "+sum);
	}
}
class Cus implements Runnable{
	private Bank b = new Bank();
	public void run(){
		for (int i = 0; i < 3; i++) {
			b.add(100);
		}
	}
}
class Cus2 implements Runnable{
	private Bank2 b2 = new Bank2();
	public void run(){
		for (int i = 0; i < 3; i++) {
			b2.add(100);
		}
	}
}
public class ThreadDemo6 {
	public static void main(String[] args) {
		Cus c = new Cus();
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);
		t1.start();
		t2.start();
		Cus2 c2 = new Cus2();
		Thread tt1 = new Thread(c2);
		Thread tt2 = new Thread(c2);
		tt1.start();
		tt2.start();
	}
}
/*
 *原因分析:
 *由代码中可以看到,同步代码块中的语句,存在可能有多个线程同时操作共享数据(sum)的情况,通过同步代码
 *块即可解决存在的安全问题. 
 */
运行结果:

sum = 100
sum = 200
sum = 300
sum = 400
sum = 500
sum = 600
sum = 100
sum = 200
sum = 300
sum = 400
sum = 500
sum = 600

package cn.fuxi.duoxiancheng;
/**
 * 由于同步函数的锁是固定的this,同步代码块的锁是任意的对象,
 * 那么如果同步函数和同步代码块都使用this作为锁,就可以实现同步.
 */
class Ticket3 implements Runnable{
	private int num = 100;
	boolean flag =true;
	
	public void run(){
		if(flag){
			while(true){
				synchronized(this){
					if(num>0){
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
					}
				}
			}
		}else{
			while(true){
				show();
			}
		}
	}
	public synchronized void show(){
		if(num>0){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"...function..."+num--);
		}
	}
}

public class ThreadDemo7 {
	public static void main(String[] args) {
		Ticket3 t = new Ticket3();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		t1.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//上面这条语句一定要执行,应为可能线程t1未真正启动,flag已经设置为false,那么当t1执行的时候,
		//就会按照flag为false的情况执行,线程t2也按照false执行,就达不到试验的目的了.
		t.flag = false;
		t2.start();
	}
}
运行结果:

Thread-1...function...15
Thread-1...function...14
Thread-1...function...13
Thread-1...function...12
Thread-1...function...11
Thread-1...function...10
Thread-0...sale...9
Thread-0...sale...8
Thread-0...sale...7
Thread-0...sale...6
Thread-0...sale...5
Thread-0...sale...4
Thread-0...sale...3
Thread-1...function...2
Thread-1...function...1

package cn.fuxi.duoxiancheng;
/**
 * 静态的同步函数使用的锁是该函数所属字节码文件对象,可以用getClass方法获取,也可以用当前类名.class表示.
 */
class Ticket4 implements Runnable{
	private static int num = 100;
	Object obj = new Object();
	boolean flag = true;
	
	public void run(){
		if(flag){
			while(true){
				synchronized(Ticket4.class){//this.getClass()
					if(num>0){
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()+"...obj..."+num--);
						
					}
				}
			}
		}else{
			while(true){
				show();
			}
		}
	}public static synchronized void show(){
		if(num>0){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"...function..."+num--);
		}
	}
}
public class ThreadDemo8 {
	public static void main(String[] args) {
		Ticket4 t = new Ticket4();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		t1.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t.flag = false;
		t2.start();
	}

}
运行结果:

Thread-1...function...21
Thread-1...function...20
Thread-1...function...19
Thread-1...function...18
Thread-0...obj...17
Thread-1...function...16
Thread-1...function...15
Thread-1...function...14
Thread-0...obj...13
Thread-1...function...12
Thread-1...function...11
Thread-1...function...10
Thread-1...function...9
Thread-1...function...8
Thread-1...function...7
Thread-1...function...6
Thread-1...function...5
Thread-1...function...4
Thread-1...function...3
Thread-0...obj...2
Thread-1...function...1

多线程下的单例模式问题:

package cn.fuxi.duoxiancheng;
/**
 * 多线程下的单里模式
 */
//P.S.饿汉式不存在安全问题,因为不存在多个线程共同操作数据的情况.
class Single{
	private Single(){}
	private static final Single s = new Single();
	public static Single getInstance(){
		return s;
	}
}
//懒汉式存在安全问题,可以使用同步函数解决.
//但若直接使用同步函数,则效率较低,因为每次都需要判断.
class Single2{
	private Single2(){}
	private static Single2 s =null;
	public static Single2 getInstance(){
		if(s==null){
			synchronized(Single2.class){
				if(s==null)
				s = new Single2();
			}
		}
		return s;
	}
}
/*
 *原因在于任何一个线程在执行到第一个if判断语句时,如果Single对象已经创建,则直接获取即可,
 *而不用判断是否能够获取锁,相对于上面使用同步函数的方法就提升了效率.如果当前线程发现Single
 *对象尚未创建,则再判断是否能够获取锁.
 *1.如果能够获取锁,那么久通过第二个if判断语句判断是否需要Single对象.因为可能当此线程获
 *取到锁之前,已经有一个线程创建完Single对象,并且放弃了锁.此时,它便没有必要再去创建,可以
 *直接跳出同步代码块,放弃锁,获取Single对象即可.如果有必要,则再创建.
 *2.如果不能获取到锁,则等待,直到能够获取到锁为止,再按步骤一执行. 
 */
public class ThreadDemo9 {
	public static void main(String[] args) {
	}
}
死锁问题:
package cn.fuxi.duoxiancheng;
/**
 * 死锁案列:同步的嵌套
 */
class Ticket5 implements Runnable{
	private static int num = 100;
	Object obj = new Object();
	boolean flag = true;
	public void run(){
		if(flag){
			while(true){
				synchronized(obj){
					show();
				}
			}
		}else {
			while(true){
				show();
			}
		}
	}
	public synchronized void show(){
		synchronized(obj){
			if(num>0){
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"...function..."+num--);
			}
		}
	}
} 

public class ThreadDemo10 {
	public static void main(String[] args) {
		Ticket5 t = new Ticket5();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		t1.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t.flag = false;
		t2.start();
	}
}
/*
 *程序运行后可以看出,程序已被锁死,无法向下执行.
 *由代码可以看出,run方法中的同步代码块需要获取obj对象锁,才能执行代码块中的show方法.
 *而执行show方法则必须获取this对象锁,然后才能执行其中的同步代码块.
 *当线程t1获取到obj对象锁执行同步代码块,线程t2获取到this对象锁执行show方法.同步
 *代码块中的show方法因无法获取到this对象锁无法执行,show方法中的同步代码块因为无法获取
 *到obj对象锁无法执行,就会产生死锁.
 */
运行结果:

Thread-1...function...63
Thread-1...function...62
Thread-1...function...61
Thread-1...function...60
Thread-1...function...59
Thread-1...function...58
Thread-0...function...57//停止了

死锁2:

package cn.fuxi.duoxiancheng;
/**
 * 死锁2
 */
class Test implements Runnable{
	private boolean flag;
	Test(boolean flag){
		this.flag = flag;
	}
	public void run(){
		if(flag){
			while(true){
				synchronized(MyLock.locka){
					System.out.println(Thread.currentThread().getName()+"...if locka...");
					synchronized(MyLock.lockb){
						System.out.println(Thread.currentThread().getName()+"...if lockb...");
					}
				}
			}
		}else{
			while(true){
				synchronized(MyLock.lockb){
					System.out.println(Thread.currentThread().getName()+"...else lockb...");
					synchronized(MyLock.locka){
						System.out.println(Thread.currentThread().getName()+"...else locka...");
					}
				}
			}
		}
	}
}
class MyLock{
	public static final Object locka = new Object();
	public static final Object lockb = new Object();
}

public class ThreadDemo11 {
	public static void main(String[] args) {
		Test a = new Test(true);
		Test b = new Test(false);
		Thread ta = new Thread(a);
		Thread tb = new Thread(b);
		ta.start();
		tb.start();

	}

}

运行结果:

Thread-1...else lockb...
Thread-0...if locka...



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值