java高级之多线程(一)

多线程的一篇文章,个人对于多线程及其一些知识点的总结。

 1.首先了解什么是线程:

线程是程序执行的路径。一个程序中可以有多条线程。

2. 多线程有什么用呢?

多线程并发可以提高程序的效率(同时执行多项任务,并发并行自己百度吧)。


多线程的两种方式:

(1)继承Thread类。


public class TextThread {
	public static void main(String[] args) {
		new FirstThread("One").start();//匿名创建线程并开启线程

	}

}

class FirstThread extends Thread {
	public FirstThread(String name) { // Thread都有一个名称 只要继承Thread方法
										// 就可以调用super方法设置名称
		super(name); // 调用父类的name
	}

	int index = 0;

	public void run() {//必须重写run方法,
		for (int index = 0; index < 100; index++) {
			System.out.println(index + Thread.currentThread().getName());//获取当前子线程的名称
		}
	}
}


(2)实现Runnable接口。

package S;

public class TextThread {
	public static void main(String[] args) {
		new TextThread().Begin();

	}

	public void Begin() {
		MyThread mt = new MyThread();
		Thread t = new Thread(mt, "天狼王");//线程t
		new Thread(mt, "王老二").start();//匿名方式启动子线程  线程2
		t.start();

	}

}

class MyThread implements Runnable { // 实现runnable接口并实现run方法

	public void run() {
		for (int i = 0; i < 100; i++) {

			System.out.println(Thread.currentThread().getName() + i);
			
		}

	}

}

打印:



* 继承Thread
* 好处是:可以直接使用Thread类中的方法,代码简单
* 弊端是:如果已经有了父类,就不能用这种方法
* 实现Runnable接口
* 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
* 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂


通过匿名内部类直接创建子线程:

方式一:

new Thread(“yyy”){//yyy线程名字

   public void run(){}

}

方式二:

new Thread(new Runnable(){ //1,new 接口(){}实现这个接口
public void run() { //2,重写run方法
for(int i = 0; i < 3000; i++) { //3,将要执行的代码,写在run方法中
System.out.println("bb");
}
}
}).start(); 

多线程的休眠线程,加入线程,守护线程和礼让线程。

(1)sleep(休眠)

public class TextThread {
	public static void main(String[] args) {
		new TextThread().Begin();

	}

	public void Begin() {
		MyThread mt = new MyThread();
		Thread t = new Thread(mt, "天狼王");
                //t.setDaemon(true);//守护线程
		t.start();

		try {

			// t.join(); //加入线程 一直等待该线程执行完 才执行别的线程
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (int i = 0; i < 100; i++) {
			System.out.println("main" + i);
			//Thread.yield();// 礼让线程  当前线程下来
		}

	}

}

class MyThread implements Runnable { // 实现runnable接口并实现run方法

	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + i);

			try {
				Thread.sleep(1000); // blocked
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}


打印:天狼王的子线程中调用了sleep方法,此线程就休息了不往下执行,因为CPU的执行速度很快(瞬间打印完毕),此时主线程就顺利抢占到CPU,打印main0......,之后子线程天狼王才打印。。。。。




(2)join(加入)

把上面的代码join一行解开注释,sleep加上注释。

打印结果:调用join方法后,调用此方法的线程会强行抢占CPU,直到此线程执行完毕,才执行其他线程。

(3)setDaemon(true);//守护线程

把上面的代码一行解开注释,其他加上注释。main方法中的i最大改成5。

打印:设置为守护线程后,当其他线程执行完毕,守护线程会立即去结束自己的这个线程,没打印出来的...100就打印不了了。


(3)yield();//礼让线程(了解)

调用此方法后,当前线程下来,让其他线程抢占CPU.


多线程(同步代码块) 使用关键字

.什么情况下需要同步
* 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
* 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.


* 2.同步代码块

(1)同步代码块:

package overClass;

public class Abnormal {

	public static void main(String[] args) {
		final Printer p = new Printer();
		new Thread() {

			public void run() {
				while (true) {
					p.print1();
				}

			}
		}.start();
		new Thread() {

			public void run() {
				while (true) {
					p.print2();

				}
			}
		}.start();

	}
}

class Printer {
	static Object d = new Object();

	public static void print1() { // 两个线程持有同一把锁,相当于两个人用一把锁开门,一个人开门后,关上了,另一个人进不去,必须等待在门里面的人出来然后把钥匙给他,才能进去
		synchronized (d) { // 锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
			System.out.print("人");
			System.out.print("间");
			System.out.print("天");
			System.out.print("堂");
			System.out.print("\r\n");
		}
	}

	public static void print2() {
		synchronized (d) {
			System.out.print("十八");
			System.out.print("层");
			System.out.print("地");
			System.out.print("狱");
			System.out.print("\r\n");
		}
	}
}

打印:


(2)同步方法:

class Printer {

	public static void print1() { // 两个线程持有同一把锁,相当于两个人用一把锁开门,一个人开门后,关上了,另一个人进不去,必须等待在门里面的人出来然后把钥匙给他,才能进去
		synchronized (Printer.class) { // 锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
			System.out.print("人");
			System.out.print("间");
			System.out.print("天");
			System.out.print("堂");
			System.out.print("\r\n");
		}
	}

	/*
	 * 非静态同步函数的锁是:this 静态的同步函数的锁是:字节码对象
	 */
	public static synchronized void print2() {

		System.out.print("十八");
		System.out.print("层");
		System.out.print("地");
		System.out.print("狱");
		System.out.print("\r\n");

	}
}
线程安全问题,多个线程修改一个变量(售票)把这个变量声明称static,避免并发带来的错误。


end:死锁(了解)有两把钥匙,线程一拿到钥匙一,缺钥匙二,而线程二拿到钥匙二,缺钥匙一,又在while循环中无法退出。造成了死锁。

private static String s1 = "筷子左";
			private static String s2 = "筷子右";
			public static void main(String[] args) {
				new Thread() {
					public void run() {
						while(true) {
							synchronized(s1) {
								System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
								synchronized(s2) {
									System.out.println(getName() + "...拿到" + s2 + "开吃");
								}
							}
						}
					}
				}.start();
				
				new Thread() {
					public void run() {
						while(true) {
							synchronized(s2) {
								System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
								synchronized(s1) {
									System.out.println(getName() + "...拿到" + s1 + "开吃");
								}
							}
						}
					}
				}.start();
			}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值