java多线程总结

一个一个敲上来的,如何错误,请多多指教!谢谢合作!








切记,垃圾回收的线程永远都是存在的!




并行和并发
并行:在一个时间段内一起运行的多个程序
并发:在某个时间点同时进行的多个程序




实现多线程,有两种方法。1:继承Thread类 2:实现Runnable接口。但实际全部都用的实现Runnable接口,应为这样还可以继承其他类。
在就是,如果是继承了Thread,那么需要 两个同一线程 的对象就必须进行两次 new ThreadTest()那个继承Thread类的对象
而实现Runnable的话,就只需要一次new Runnable()对象,然后Runnable runnable = new RunnableTest();那个实现Runnable接口的对象
Theared t1 = new Thread(runnable);
Theared t2 = new Thread(runnable);
Theared t3 = new Thread(runnable);
这里其实就只对那个要用的线程进行了一次new;
关于New了几个对象,其实关键问题是,如果在线程类里面有一个成员变量,如果使用第一种方法,那么每次new都是新造了一个对象,里面的成员变量就是一个新的对象,而使用第二种方法,那么不论你下面用多少次我的线程类,但是我的该类只进行了一次的new,所以里面的成员变量就可以一直使用的是同一个对象。也就是说我用不同的线程对象,调用的却是同一个成员变量。(回想三个窗口买电影票的问题)
其实这就引出了--------同步机制-------的问题!





Thread类中有几个重要的方法 getName() 获取线程对象的线程名
Thread.currentThread() 获取当前的线程对象
构造方法 new Thread(Runnable r, String s) 传入一个实现了Runnable的对象,为该线程对象指定线程名


设置线程的优先级 setPrioeity() 优先级只是指定它占用时间段的片段多一点,但要在大程序中才能最好的体现,小程序没什么大的现实效果。


使线程进入休眠 sleep()


等待线程终止 join() 也就是说,线程对象调用该方法后,其他在该对象后面的线程必须先等待该线程执行结束后,才能执行。
礼让方法 yiele() 在run方法中用Thread调用该方法,实现。意思是,你一步我一步,但是,不是一定能够这样,只能说尽量,也有可能发生错乱。
设置守护线程 setDaemon(Boolean) 传入的是一个布尔值,true这表示设置为守护线程为真。
守护线程的特点是:就是没什么特点,和普通线程差不多。主要是主线程完毕了,他也就GAMEOVER了。
个人觉得守护线程可以和线程组一起配合使用。
终止线程 interrupt()这个的原理是,抛出一个异常,然后继续执行run()中,catch{}下面的代码。也就是说清除阻塞的作用
个人觉得它的使用场景应该是:


同步机制
synchronized(锁){ //锁,可以直接用this对象,这样就保证了每次走该线程的这段代码的锁都是一致的
需要锁住的代码块
}
public synchronized void funcName(){ //表示只要是由synchronized修饰的方法,表示被this锁锁住的代码块
需要锁定的代码块
}
例子:三个窗口卖票
Thread类
package cn.xiongchun.iterator.multithreading;


public class MyThread implements Runnable{

private int num = 100;


@Override
public void run() {

while(num>0){
try {
verification();

//测试Num=0的时候是否还进while循环
// if(num == 0){
// System.out.println("0张票的时候还进来么?");
// //结论得出,当Num=1的时候,三个线程可以就已经全部都强到了,然后都停在方法前,然后
// //假设t1带着num=1进去,然后出来,num=0了,而t2/t3已经走到方法这里,所以,虽然没进方法里面
// //但是还是在while里面的,所以也就会输出这段话
// }

} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


private synchronized void verification() throws InterruptedException {

if(num > 0){
num --;
if(num!=0){
System.out.println("还剩"+num+"张票");------这里要注意要先减,在输出,否则就是输出100了
}else{
System.out.println("票以卖完!!");
}
// Thread.sleep(100);
}

}


}
-----------------------------------------------------------------------------------------


测试类
package cn.xiongchun.iterator.multithreading;


public class Test1 {


public static void main(String[] args) {
MyThread my = new MyThread();

Thread t1 = new Thread(my, "1售票口");
Thread t2 = new Thread(my, "2售票口");
Thread t3 = new Thread(my, "3售票口");

t1.start();
t2.start();
t3.start();

}


}
打印结果
还剩99张票
还剩98张票
还剩97张票
   .
   .
   .
   .
   .
   .
还剩3张票
还剩2张票
还剩1张票
票卖完了!!


Lock接口
1.5后提供的,它有几个实现类ReentrantLock,其中有两个方法:1.lock()2.unLuck分别是用来上锁和解锁的
Lock look = new ReentrantLock();
private void verification() {
look.look(); //在这里上锁
if(num > 0){
num --;
if(num!=0){
System.out.println("还剩"+num+"张票");------这里要注意要先减,在输出,否则就是输出100了
}else{
System.out.println("票以卖完!!");
}
}
look.unlook(); //在这里解锁
}


生产者消费者模式
首先建立一个中间产产品
package cn.xiongchun.iterator.producerAndCustomer;


public class Student {

private String name;
private int age;

private boolean flag;//设置一个状态变量,判断现在是否是需要生产,如果为false,则表示还没有生产,所以进入生产状态,然后改变为true(以生产状态)

public synchronized void set(String name,int age){

if(this.flag==false){
this.name = name;
this.age = age;
this.flag = true;-----------------------------------改变为以生产状态
this.notify();//唤醒线程
}else{
try {
this.wait();//使线程等待唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public synchronized void get(){

if(this.flag!=false){
System.out.println("Student-name:"+this.name+"/n    age=  "+age);
this.flag = false;-----------------------------------改变为未生产状态
this.notify();//唤醒线程
}else{
try {
this.wait();//是线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


}
--------生产者(只管生产)但要判断状态变量是否是需要生产的状态
package cn.xiongchun.iterator.producerAndCustomer;


public class Producer implements Runnable{

Student s = new Student();

private int i = 0;

public Producer(Student s){
this.s = s;
}


@Override
public void run() {

while (true) {
if(i%2==0){
s.set("熊---春", 20);
}else{
s.set("夏青", 22);
}
i++;
try {
Thread.sleep(100);//睡0.1秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

}
------------消费者
package cn.xiongchun.iterator.producerAndCustomer;


public class Customer implements Runnable{

Student s = new Student();

public Customer(Student s){
this.s = s;
}
int i = 100;//这里指定循环100次


@Override
public void run() {


while(i>0){
s.get();
i--;
}
try {
Thread.sleep(100);//睡0.1秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


}
-------测试类
package cn.xiongchun.iterator.producerAndCustomer;


public class Demo {
public static void main(String[] args) {
Student s = new Student();

Thread p = new Thread(new Producer(s));
Thread c = new Thread(new Customer(s));

p.start();
c.start();

}


}
--------------打印结果
Student-name:熊---春/n    age=  20
Student-name:夏青/n    age=  22
Student-name:熊---春/n    age=  20
Student-name:夏青/n    age=  22
Student-name:熊---春/n    age=  20---------几乎都是交换出现,这主要是我的sleep()方法,如果没有该方法,那么久是随机强的了。
----交替出现我想应该是必然的,因为0.1秒已经完全足够另一个线程干完另一件事情了。
----但是,如果是干比较繁重的事情,比如说文件的写入写出等等,那么就不一定了,因为在0.1秒做不做得完又是另一回事情了。




多线程组
package cn.xiongchun.iterator.producerAndCustomer;


public class Demo {
public static void main(String[] args) {
Student s = new Student();

ThreadGroup tg = new ThreadGroup("我是一个线程组");

Thread p = new Thread(tg,new Producer(s),"我是生产者线程");
Thread c = new Thread(tg,new Customer(s),"我是消费者线程");

System.out.println(p.getName()+"----我的线程组组长是----"+p.getThreadGroup().getName());
p.start();
System.out.println(c.getName()+"----我的线程组组长是----"+c.getThreadGroup().getName());
c.start();
}
}
------------输出结果
我是生产者线程----我的线程组组长是----我是一个线程组
我是消费者线程----我的线程组组长是----我是一个线程组
Student-name:熊---春/n    age=  20
Student-name:熊---春/n    age=  20
Student-name:熊---春/n    age=  20
Student-name:熊---春/n    age=  20
Student-name:熊---春/n    age=  20.....................


线程池---与Callable
Callable是一个依赖于线程池的第三种可以实现多线程的接口
它的特点是可以带一个返回值(具体请查API)




现在用它来实现两个线程各自算各自的和


---------首先创建一个实现了Callabel的类,和实现其中的算法与run()
package cn.xiongchun.iterator.callable;


import java.util.concurrent.Callable;


public class MyCallable implements Callable<Integer> {

private Integer i;

public MyCallable(Integer i) {
this.i = i;
}


@Override
public  Integer call() throws Exception {
Integer sum = 0;
for(int j = 0; j<=i; j++){
sum+=j;
}
return sum;
}


}


----------在测试类
package cn.xiongchun.iterator.callable;


import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class CallableTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {

//Executors有一个静态方法newFixedThreadPool(int Callable<V>)
//指定几个Callable线程,并且返回值是一个线程池对象
ExecutorService pool =Executors.newFixedThreadPool(2);

//如果直接pool.submit(new MyCallable());也就相当于一个Thread对象.start()
//线程池对象的submit()方法,传入一个Callable对象,然后执行,返回一个Future对象的结果
//查API可以发现,Future有一个方法get(),获得结果
Future<Integer> result1 =  pool.submit(new MyCallable(5));
Future<Integer> result2 = pool.submit(new MyCallable(10));

System.out.println(result1.get());
System.out.println("--------------");
System.out.println(result2.get());

pool.shutdown();

}


}
---------结果
15
--------------
55








定时器
Timer 该类可以安排线程定时运行一次,或者重复多次。主要是定时功能
TimerTask 定时器的任务,主要负责的是任务,也就是要执行的事情(让一个类继承该类,实现其中的run方法)


具体用一个例子来说明 指定某段---时间段以后--执行该任务(删除指定目录)




-------------首先先写一个实现了TimerTask的任务线程
package cn.xiongchun.iterator.multithreading.timer;


import java.io.File;
import java.util.Timer;
import java.util.TimerTask;


public class MyTimerTask extends TimerTask{

private Timer t;

public MyTimerTask(Timer t) {
this.t = t;
}


@Override
public void run() {
File srcForlder = new File("F:\\aa");
deletForlder(srcForlder);
t.cancel(); //关闭线程
}
//递归删除文件以及文件夹
private void deletForlder(File srcForlder) {
File[] files = srcForlder.listFiles();
if(files != null){
for(File file: files){
if(file.isDirectory()){
deletForlder(file);
}else{
System.out.println(file.delete()+"删除的文件是:"+file.getName());
}
}
System.out.println(srcForlder.delete()+"文件夹被删除:"+srcForlder.getName());
}

}


}
--------然后在定时类
package cn.xiongchun.iterator.multithreading.timer;


import java.util.Timer;


public class Demo {

public static void main(String[] args) {
Timer timer = new Timer();

timer.schedule(new MyTimerTask(timer), 1000);//指定1000毫秒后执行某线程任务
}


}
--------打印结果
true删除的文件是:snmpapp.conf
true文件夹被删除:PERSIST
true文件夹被删除:SNMP
true文件夹被删除:USR
true文件夹被删除:aa






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值