java多线程编程核心技术1-Thread基础知识

一。Java多线程技能:
1. 一个进程正在运行时至少会有一个线程正在运行,main方法的线程是由JVM创建的,通过jps能检测到。
2. 使用多线程技术时,代码的运行结果与代码的执行顺序或调用顺序是无关的。
3. new Thread(Runnable target)不只可以传入Runnable接口的对象,还可以传入另一个Thread类的对象,完全可以将一个Thread对象中的run()
   方法交由其他的线程进行调用。
4. 在main方法中创建线程并调用其start(),线程的构造方法是在main线程里执行的,run方法在对应的线程里执行,但是如果直接调用线程的run方法,则其也是在main线程里执行的。
5. isAlive()方法:判断当前的线程是否处于活动状态,注意:将线程对象以构造参数的方式传递给Thread对象进行start()时,this指的时线程对象, Thread.currentThread()或this.Thread.currentThread()指的时Thread对象,Thread对象时存活的(isAlive())
6. Thread.sleep()方法:让当前线程休眠,如果在main方法里通过调用线程类的run方法执行线程,则虽然Thread.sleep()在run方法里,休眠的仍然是main线程(可通过打印this.currentThread().getName()印证)   
7. getId()方法的唯一作用是取得线程的唯一标识。



二。线程的中断:

1.通过interrupt()中断:
1. thread.interrupt(): 中断thread对象所代表的线程。
2. Thread.currentThread().interrupt(): 中断当前线程。
3. this.interrupted()/Thread.interrupted(): 测试当前线程是否已经中断,如果已被设置中断标记,调用过一次后会清除此标记,导致再次调用没有。
4. this.isInterrupted()/Thread.isInterrupted():测试线程是否已经中断,调用后不清除中断标记。


2.通过异常法中断:

    1.通过在线程的run方法中的for循环里判断线程是否停止状态(this.interrupted())。

	public class MyThread1 extends Thread {
		@Override
		public void run() {
			super.run();
			for (int i = 0; i < 500000; i++) {
				if (this.interrupted()) {
					System.out.println("已经是停止状态了!我要退出了!");
					break;
				}
				System.out.println("i=" + (i + 1));
			}
			System.out.println("如果我会for循环又会继续运行......");
		}
	}

2.为了避免中断后for下面的语句仍然运行,需要中断时抛出中断异常并处理中断。
	public class MyThread1 extends Thread {
		@Override
		public void run() {
			super.run();
			try {
				for (int i = 0; i < 500000; i++) {
					if (this.interrupted()) {
						System.out.println("已经是停止状态了!我要退出了!");
						throw new InterruptedException();
					}
					System.out.println("i=" + (i + 1));
				}
				System.out.println("如果我会for循环又会继续运行......");
			} catch (InterruptedException e) {
				System.out.println("进MyThread.java类run方法中的catch了!");
				e.printStackTrace();
			}
		}
	}



3.在睡眠中停止线程:
1.先sleep再interrupt:如果在sleep状态下停止某一线程,会进入catch语句并且清除停止状态值,使之变成false,sleep之后的程序不会执行。
2.先interrupt再sleep:如果在sleep之前还有程序如for循环,调用中断后并不会影响for循环的执行,等执行到sleep时才进入catch语句并且清除停止状态值,使之变成false。
	public class MyThread1 extends Thread {
		@Override
		public void run() {
			super.run();
			try {
				// 调用此线程的interrupt方法是,for循环会正常执行完毕
				for (int i = 0; i < 500000; i++) {
					System.out.println("i=" + (i + 1));
				}
				System.out.println("run begin");
				Thread.sleep(200000);
				System.out.println("run end");
			} catch (InterruptedException e) {
				System.out.println("先停止,再遇到了sleep!进入catch!");
				e.printStackTrace();
			}
		}
	}




4.暴力停止线程:
  1.thread.stop():是一个depreated方法,线程被暴力停止(stop)运行后图标呈灰色,调用stop方法时会抛出ThreadDeath异常,通常不需要显示的捕捉
  2.缺点:1.强制停止线程可能使一些请理性的工作得不到完成。
        2.对锁定的对象进行了“解锁”,导致数据得不到同步的处理,出现数据不一致的问题。
  


5.使用return停止线程:
  1.将方法interrupt()与return结合使用也能实现停止线程的效果。
	public class MyThread1 extends Thread {
		@Override
		public void run() {
			while (true) {
				if (this.isInterrupted()) {
					System.out.println("停止了!");
					return;
				}
				System.out.println("timer=" + System.currentTimeMillis());
			}
		}
	}




三。暂停线程:
1. 使用suspend()方法暂停线程,使用resume()方法恢复线程的执行。
   缺点1-独占:
   1.极易造成公共对象的独占,使得其他线程无法访问公共同步对象。
           如一个线程进入了一个公共对象的同步方法内suspend()了后,由于始终占据锁不放,所以其他线程无法进入这个公共对象的此同步方法内。
	public class SynchronizedObject {
		synchronized public void printString() {
			System.out.println("begin");
			if (Thread.currentThread().getName().equals("a")) {
				System.out.println("a线程永远 suspend了!");
				Thread.currentThread().suspend();
			}
			System.out.println("end");
		}
	}


2.另一种独占情况,当把run方法中的打印语句放开后,main方法里的打印语句不会执行,因为打印方法prinln内部实现是同步的代码块
 分为打印和换行两步,当程序运行到代码块内部suspend时,打印语句的锁不会释放,导致main方法里的打印语句不能执行。
	public class MyThread extends Thread {
		private long i = 0;

		@Override
		public void run() {
			while (true) {
				i++;
				// System.out.println(i);
			}
		}
	}

	public class Run {
		public static void main(String[] args) {
			try {
				MyThread thread = new MyThread();
				thread.start();
				Thread.sleep(1000);
				thread.suspend();
				System.out.println("main end!");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}


缺点2-不同步:
1.容易出现因为线程的暂停而导致数据不同步的情况。
 即如果设置共享对象多个值中间suspend了线程,导致此对象的值只被设置了一部分,从而其他线程使用该对象时出现了值不一致的情况。




四.yield方法:
  作用:放弃当前的CPU资源,将它让给其他的任务,但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU的时间片。
  如下示例:for循环中每次都yield一次,等待再次获取,总的执行时间将呈几何倍增加。  
	public class MyThread1 extends Thread {
		@Override
		public void run() {
			long beginTime = System.currentTimeMillis();
			int count = 0;
			for (int i = 0; i < 50000000; i++) {
				// Thread.yield();
				count = count + (i + 1);
			}
			long endTime = System.currentTimeMillis();
			System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
		}


	}



五。线程的优先级:
1. setPriority():用于设置线程的优先级,优先级较高的线程获得的CPU资源较多,设置优先级有助于帮“线程规划器”确定下一次选择哪一个线程来优先执行。
   线程优先级分为1~10这10个等级,不在此范围内的优先级会抛出异常,常用1,5,10标识低、中、高优先级。
2.线程优先级的继承特性:A线程启动B线程,则B线程的优先级与A是一样的。
3.线程的优先级具有规则性:
  1.优先级高的大部分情况下是先执行完的,尽管它可能启动时间可能晚于其他低优先级的线程。   
  2.“随机性”,优先级较高的线程不一定每一次都先执行完。
4.结论:不要把线程的优先级与运行结果的顺序作为衡量的标准,优先级较高的线程并不一定每一次都先执行完run()方法中的任务。



六。守护线程:
1. 当进程中没有非守护线程时,则守护线程自动销毁。 Daemon为其他线程的运行提供便利服务,守护线程最经典的应用就是GC垃圾回收器。
2. 通过thread.setDaemon(true)来设置一个线程为守护线程。
   
	public class MyThread1 extends Thread {
		private int i = 0;

		@Override
		public void run() {
			try {
				while (true) {
					i++;
					System.out.println("i=" + (i));
					Thread.sleep(100);
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public class MyTest2 {
		public static void main(String[] args) throws InterruptedException {
			try {
				MyThread1 thread = new MyThread1();
				thread.setDaemon(true);
				thread.start();
				Thread.sleep(5000);
				System.out.println("我离开thread对象也不再打印了,也就是停止了!");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}


















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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值