一,创建线程的方式一——继承Thread类,重写run方法
线程类:
public class MyThread extends Thread{
@Override
public void run() {
for(int i = 0;i<20;++i)
{
System.out.println("id:"+this.getId()+" name:"+this.getName()+" i="+i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
MyThread myThread2 = new MyThread();
myThread2.setName("我的线程");
myThread2.start();
}
}
运行结果: (1)获得线程Id和线程名称 ①在Thread的子类中调用this.getId(); 或this.getName(); 分别获得id和名称。——只适合继承Thread类的子类中
②使用Thread.currentThread().getId(); 或Thread.currentThread().getName(); 的方式。——通用
(2)修改线程名称(线程id不可修改) ①调用线程对象的setName()方法。——需要在启动前修改
②构造函数,在类中添加带参构造函数用于设置线程名称 从源码可以看出,Thread类中具有在创建线程对象时设置线程名称的构造函数,如下图: 在程序中的用法:
public MyThread(String name)
{
super(name);
}
MyThread myThread2 = new MyThread("我的线程");
myThread2.start();
二,创建线程的方式2——实现Runnable接口,重写run方法
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 0; i<10; ++i)
{
System.out.println("id:"+Thread.currentThread().getId()+" name"+Thread.currentThread().getName()+" i:"+i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyRunnable myrunnable = new MyRunnable();
Thread thread = new Thread(myrunnable,"我的线程1");
thread.start();
Thread thread2 = new Thread(myrunnable,"我的线程2");
thread2.start();
}
}
匿名内部类:
public static void main(String[] args) {
Runnable runnable = new Runnable(){
@Override
public void run() {
for(int i=0;i<10;++i)
{
System.out.println("id:"+Thread.currentThread().getId()+" name:"+Thread.currentThread().getName()+" i:"+i);
}
}
};
Thread thread = new Thread(runnable,"我的线程");
thread.start();
}
当这个对象只会创建一次线程时:
new Thread(new Runnable(){
@Override
public void run() {
for(int i=0;i<10;++i)
{
System.out.println("id:"+Thread.currentThread().getId()+" name:"+Thread.currentThread().getName()+" i:"+i);
}
}
},"我的线程").start();
三,创建线程的方式三——实现Callable接口,重写call()方法
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() {
private Integer sum = 0;
@Override
public Integer call() throws Exception {
for(int i=0;i<10;++i)
{
sum+=i;
System.out.println("id:"+Thread.currentThread().getId()+" name"+Thread.currentThread().getName()+" sum:"+sum);
}
return sum;
}
};
FutureTask<Integer> task = new FutureTask<>(callable);
Thread thread = new Thread(task);
thread.start();
Integer sum = 0;
try {
sum = task.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(sum);
}
}
Furture接口表示将要完成任务的结果,后期还有深入学习。
四,线程中常用方法
1,public static void sleep(long millis); 当前执行的线程主动停止运行一段millis毫秒的时间。
2,public static void yield(); 当前执行的线程主动暂定。放弃时间片,回到就绪状态,等待下一次时间片。
3,public final void join(); 允许其他线程加入当前线程中,将当前线程阻塞,直到加入的线程执行完毕。
4,线程对象.setPriority() 和getPriority() 设置线程的优先级和获得线程的优先级!
线程的优先级为1-10,优先级越高表示获得CPU机会越多,默认为5。
5,线程对象.setName()和getName() 设置线程的名称和获得线程的名称
6,线程对象.getId() 获得线程的名称
7,线程对象.isAlive() 判断线程是否终止
8,Thread.currentThread() 获得当前正在运行线程的对象
9,线程对象.setDaemon(true); 设置该线程为守护线程
线程: ①用户线程(前台线程) ②守护线程(后台线程) . 如果程序中所有前台线程都执行完毕了,后台线程就会自动结束 垃圾回收器属于守护线程
五,线程安全
多线程并发访问临界资源,破坏了原子性而造成数据不一致。 以上代码两个线程thread和thread2公用了一个MyRunnable对象,而该类中有变量sum,即是两个线程共用一个变量sum,于是造成: 1,同步方式1——同步代码块
synchronized(sum)
{
System.out.println("线程id:"+Thread.currentThread().getId()+" sum:"+sum);
sum--;
}
对临界资源对象sum进行加锁,锁中的代码将具有原子性,要么都不执行,要么都执行。
synchronized(临界资源对象){//对临界资源对象加锁 //代码 (原子操作) } . 括号中的临界资源对象,需是引用 类型 Object o = new Object();创建的对象也可 可用this
运行结果:
2,同步方式2——同步方法
synchronized void printSum()
{
while(sum>=0)
{
System.out.println("线程id:"+Thread.currentThread().getId()+" sum:"+sum);
sum--;
}
}
相当于对当前对象(this)加锁 如果是静态方法,相当于对当前类加锁,即对MyRunnable.class加锁
3,锁 …
4,已知的线程安全的容器类 CopyOnWriteArraySet、CopyOnWriteArrayList、ArrayBolckingQueue、LinkedBlockingQueue、ConcurrentLinkedQueue和vector都是线程安全的容器,Vector的性能比较低,基本不用。
ConcurrentSkipListMap、ConcurrentHashMap是线程安全的。
六、线程池
线程是内存资源,即会占用内存,当系统创建很多线程时容易造成内存溢出,并且频繁的创建和销毁线程时会增加资源开销造成性能下降。
故,引入线程池,预先创建线程对象并存入线程池中,需要使用线程时从池中取线程对象,使用完后将线程对象归还至线程池,重用线程池中的线程对象,避免频繁的创建与销毁;线程池可设定线程分配的数量上限。
…(线程池这么重要的东西,不得在分一篇)
大概就梳理的这么多吧,都是挺基础的东西,但对我来说可是从0到有,从不知道多线程到了解了这么多,慢慢深入研究吧。
|