线程的基本操作

初始线程:
1.新建线程
1)继承Thread类 2)实现Runnable接口
2.线程终止
除非你很清楚你在做什么,否则不要随便使用stop()方法来停止一个线程。因为stop()方法太过于暴力,强行把执行到一半的线程终止,可能会引起一些数据不一致的问题。 通过定义标记变量stopme,当stopme=true时,在run内部返回结果或跳出循环。
3.线程中断
线程中断是一种重要的线程协作机制。严格地讲,线程中断并不会使线程立即退出,而是给线程发送一个通知,告知目标线程,有人希望你退出啦!至于目标线程接到通知后如何处理,则完全由目标线程自行决定。
Thread类中与线程中断有关的,有三个方法:

注意:Thread.sleep()方法由于中断而抛出异常,此时,它会清除中断标记,如果不加处理,那么在下一次循环开始时,就无法捕获这个中断,故在异常处理中,再次设置中断标记位。
01 public static void main(String[] args) throws InterruptedException {
02 Thread t1=new Thread(){
03 @Override
04 public void run(){
05 while(true){
06 if(Thread.currentThread().isInterrupted()){
07 System.out.println("Interruted!”);
08 break;
09 }
10 try {
11 Thread.sleep(2000);
12 } catch (InterruptedException e) {
13 System.out.println("Interruted When Sleep”);
14 //设置中断状态
15 Thread.currentThread().interrupt();
16 }
17 Thread.yield();
18 }
19 }
20 };
21 t1.start();
22 Thread.sleep(2000);
23 t1.interrupt();
24 }
4.等待(wait)和通知(notify)
Object类提供两个重要的接口,线程等待wait()方法和通知notify()方法,并不是Thread类中的方法。
当线程A中,调用了obj.wait()方法,那么线程A就会停止继续执行,而转为等待状态。等待到何时结束呢?线程A会一直等到其他线程调用了obj.notify()方法为止。这时,obj对象就俨然成为多个线程之间的有效通信手段。
注意:Object.wait()和Thread.sleep()方法都可以让线程等待若干时间。除了wait()可以被唤醒外,另外一个主要区别就是wait()方法会释放目标对象的锁,而Thread.sleep()方法不会释放任何资源。
wait和notify()调用前,也必须获得object的监视器。
5.挂起(suspend)和继续执行(resume)线程
属于Thread的api,不推荐使用,因为suspend()在导致线程暂停的同时,并不会去释放任何锁资源。此时,其他任何线程想要访问被它暂用的锁时,都会被牵连,导致无法正常继续运行。直到对应的线程上进行了resume()操作,被挂起的线程才能继续,从而其他所有阻塞在相关锁上的线程也可以继续执行。但是,如果resume()操作意外地在suspend()前就执行了,那么被挂起的线程可能很难有机会被继续执行。
6.等待线程结束(join)和谦让(yield)
此时,这个线程就需要等待依赖线程执行完毕,才能继续执行。JDK Thread提供了join()操作来实现这个功能,

第一个join()方法表示无限等待,它会一直阻塞当前线程,直到目标线程执行完毕。第二个方法给出了一个最大等待时间,如果超过给定时间目标线程还在执行,当前线程也会因为“等不及了”,而继续往下执行。

join()的本质是让调用线程 wait()在当前线程对象实例上,,值得注意的一点是:不要在应用程序中,在Thread对象实例上使用类似wait()或者notify()等方法,因为这很有可能会影响系统API的工作,或者被系统API所影响。

另外一个比较有趣的方法,是Thread.yield(),它的定义如下:public static native void yield();
这是一个静态方法,一旦执行,它会使当前线程让出CPU。但要注意,让出CPU并不表示当前线程不执行了。当前线程在让出CPU后,还会进行CPU资源的争夺,但是是否能够再次被分配到,就不一定了。因此,对Thread.yield()的调用就好像是在说:我已经完成一些最重要的工作了,我应该是可以休息一下了,可以给其他线程一些工作机会啦!如果你觉得一个线程不那么重要,或者优先级非常低,而且又害怕它会占用太多的CPU资源,那么可以在适当的时候调用Thread.yield(),给予其它线程机会。

分门别类的管理:线程组
ThreadGroup tg = new ThreadGroup(“tg”);
Thread t1 = new Thread(tg, new ThreadGroupName(), "T1”);
tg.activeCount();
tg.list();
烈建议大家在创建线程和线程组的时候,给它们取一个好听的名字,方便调试

驻守后台:守护线程(Daemon)
守护线程是一种特殊的线程,就和它的名字一样,它是系统的守护者,在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程。与之相对应的是用户线程,用户线程可以认为是系统的工作线程,它会完成这个程序应该要完成的业务操作。如果用户线程全部结束,这也意味着这个程序实际上无事可做了。守护线程要守护的对象已经不存在了,那么整个应用程序就自然应该结束。因此,当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出。

先干重要的事:线程优先级
在Java中,使用1到10表示线程优先级。一般可以使用Thread内置的三个静态标量表示:
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
数字越大则优先级越高,但有效范围在1到10之间。下面的代码展示了优先级的作用。高优先级的线程倾向于更快地完成。

线程安全的概念与synchronized
线程安全是并行程序的根本和根基。
大家还记得那个多线程读写long型数据的案例吧!这就是一个典型的反例。但在使用volatile关键字后,这种错误的情况有所改善。但是,volatile并不能真正的保证线程安全。它只能确保一个线程修改了数据后,其他线程能够看到这个改动。但当两个线程同时修改某一个数据时,却依然会产生冲突。
synchronized的用法
?指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
?直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
?直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

除了用于线程同步、确保线程安全外,syn-chronized还可以保证线程间的可见性和有序性。从可见性的角度上讲,synchronized可以完全替代volatile的功能,只是使用上没有那么方便。就有序性而言,由于synchronized限制每次只有一个线程可以访问同步块,因此,无论同步块内的代码如何被乱序执行,只要保证串行语义一致,那么执行结果总是一样的。而其他访问线程,又必须在获得锁后方能进入代码块读取数据,因此,它们看到的最终结果并不取决于代码的执行过程,从而有序性问题自然得到了解决(换言之,被synchronized限制的多个线程是串行执行的)。

在Java中,Integer属于不变对象。也就是对象一旦被创建,就不可能被修改。也就是说,如果你有一个Integer代表1,那么它就永远表示1,你不可能修改Integer的值,使它为2。那如果你需要2怎么办呢?也很简单,新建一个Integer,并让它表示2即可。
使用javap反编译i++ 实际上使用了Integer.valueOf()方法新建了一个新的Integer对象,并将它赋值给变量i。也就是说,i++在真实执行时变成了:i=Integer.valueOf(i.intValue()+1);
进一步查看Integer.valueOf(),我们可以看到:public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i);}

使用jstack工具显示程序的线程信息,如下所示。其中jps可以显示当前系统中所有的Java进程。而jstack可以打印给定Java进程的内部线程及其堆栈。

C:\Users\geym >jps
14240 HashMapMultiThread
1192 Jps
C:\Users\geym >jstack 14240

时间: 2024-10-05 05:42:20

线程的基本操作的相关文章

基于List线程表基本操作

package com.cn.list.base; import java.util.ArrayList;import java.util.List; /** * 基于List线程表基本操作 * */public class ListOperation<T> { private List<T> list = null; /** * 初始化List线性表 * * @param initialCapacity 线程表容量 * @return List */ public List<

线程的基本操作(一)

查看当前线程名称--name属性 使用name属性,可以查看当前线程名称,如下: 暂停当前线程--Sleep方法 Thread类的sleep静态方法用于将当前线程暂停指定的一段时间. 它有两个重载方法: Publicstatic void Sleep(int millisecondsTimeout); Public static void sleep(timespan timeout); sleep方法最常见的应用是作为一个计时器,在写while循环中,比如进行两个系统见的数据同步: While

线程的基本操作(读书笔记)

新建线程 新建线程很简单,只要使用new关键字创建一个线程对象.并且将它start()起来即可.那么线程start()后,会干什么呢?这才是问题的关键.线程Tread,有一个run()方法.start()方法就会新建一个线程并让这个线程执行run()方法 Thread t1 = new Thread(); t1.start(); 这里要注意 下面的代码也能通过编译,也能正常运行.但是 却不能新建一个线程,而是在当前线程中调用run方法,只是当做一个普通方法调用 Thread t2 = new T

线程的基本操作,创建线程,结束线程,新线程跟原线程共享变量

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> // 包含线程库 #include <string.h> void *thread_function(void *arg); // 定义线程函数原型 //char message[] = "THREAD_TEST"; // 定义公用的内存空间 char message[

线程的基本操作(二)

前台线程和后台线程 默认情况下,新建的线程为前台线程(foreground thread),可以通过thread类的实例属性IsBackground来查看.将IsBackground设置为true时,则将线程设置为了后台线程.(Background thread). 前台线程和后天线程区别:所有前台线程执行完毕之后,应用程序进程结束,而不论后台线程是否结束. 输出的worker线程中有background标记,表示为后台线程. Suspend()和Resume()方法--线程同步 Abort()

线程的基本操作2

等待(wait) 和通知(notify) 这两个方法来自Object类, 使用前必须先获得目标的锁. wait()使用场景必须包含在synchronzied语句中., 当调用后,线程释放锁, 进入object对象的等待队列, 等待notify() .notifyAll()去唤醒. package threads; public class WaitAndNotify { final static Object ob = new Object(); public static class T1 e

线程的基本操作3

线程组:   当线程数量较多,且功能比较明确时可以将类似的线程放到一起. public class ThreadGroupName implements Runnable{ @Override public void run() { Thread thread = Thread.currentThread(); String name = thread.getThreadGroup().getName()+" : "+thread.getName(); while(true) { Sy

线程的基本操作-完

线程安全是多线程开发的根基, 我们能够使用volatile保证变量更新的数据其他线程能够看到, 但是如果两个线程同时操作一个数据, 线程安全无法保证. 下面的例子中, i的结果大概率小于我们预期的200000, 原因就在于T1,T2同时获取i值, 先后写入同一个结果. public class Sync implements Runnable { private static Sync sync = new Sync(); public volatile static int i = 1; pu

java进阶06 线程初探

线程,程序和进程是经常容易混淆的概念. 程序:就是有序严谨的指令集 进程:是一个程序及其数据在处理机上顺序执行时所发生的活动 线程:程序中不同的执行路径,就是程序中多种处理或者方法. 线程有两种方法实现 一:继承Thread 覆盖run方法 package Thread; public class Thread1 { public static void main(String[] args){ MyThread1 thread1=new MyThread1(); thread1.setName