java多线程基础部分探究

时间:2021-08-23 20:01:23

1.多线程实现方式

1.继承Thread类,但是对于单继承的Java,限制很大

2.实现Runnable接口


public class DemoThread {


public static void main(String[] args) {
Play play = new Play();
Thread thread = new Thread(play);
thread.start();
}

}


class Play implements Runnable{


@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i<10;i++){
System.out.println("线程:"+i);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println();
}
}


3.使用Timer和TimerTask组合

最后一种实现多线程的方式,就是使用java.util包中的Timer和TimerTask类实现多线程,使用这种方式也可以比较方便的实现线程。
在这种实现方式中,Timer类实现的是类似闹钟的功能,也就是定时或者每隔一定时间触发一次线程。其实,Timer类本身实现的就是一个线程,
只是这个线程是用来实现调用其它线程的。而TimerTask类是一个抽象类,该类实现了Runnable接口,所以按照前面的介绍,该类具备多线程的能力。
在这种实现方式中,通过继承TimerTask使该类获得多线程的能力,将需要多线程执行的代码书写在run方法内部,然后通过Timer类启动线程的执行。
在实际使用时,一个Timer可以启动任意多个TimerTask实现的线程,但是多个线程之间会存在阻塞。所以如果多个线程之间如果需要完全独立运行的话,
最好还是一个Timer启动一个TimerTask实现。

public class DemoTimerMark {


public static void main(String[] args) {
Timer timer1 = new Timer();
Timer timer2 = new Timer();
MyTimerTask task1 = new MyTimerTask(1);
timer1.schedule(task1, 1000);
MyTimerTask task2 = new MyTimerTask(2);
timer2.schedule(task2, 1000);

}
}


class MyTimerTask extends TimerTask{


private int count;
public MyTimerTask(int i){
this.count = i;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i<4;i++){
System.out.println("线程"+this.count+":"+i);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("========================================END=====================================");
}

}
//

2,线程状态

1.新生状态 new
2.被阻塞状态 blocked
3.可运行状态 runnable
4.等待 waiting
5.计时等待 time waiting
6.被终止 terminated

3.线程细节

1.线程优先级
setPriority方法可以为线程设置优先级 ,优先级默认继承父线程的优先级 ,线程优先级高度依赖于操作系统。Java线程优先级会被映射到寄主主体平台的优先级上面
2.守护线程 setDaemon(true)
为其他线程提供服务的线程。如计时器线程。当只有一个守护线程时,虚拟机会退出(守护线程永远不要去访问固件资源,因为他会随时中断)

4.锁   方法一:Lock/Condition  方法二:synchronized

1.条件对象
一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。当调用signalAll()方法,又可以唤醒该条件下的等待的线程。
有关Condition接口的API可以具体参考JavaAPI文档。
2.synchronized 用此关键词声明的方法必须要获得程序的内部锁

3.同步阻塞 使用一个对象的锁来实现额外的原子操作称为 客户端锁定


5,银行取款问题

// 银行取款问题
// 不加锁
public class BankProblem {

public static void main(String[] args) {
Bank bank = new Bank();
for(int i=0;i<1000;i++){
Transable transable = new Transable(bank,i);
Thread thread =new Thread(transable);
thread.start();
}
}
}
class Bank{
private int[] count = new int[10];
public Bank(){
for(int i=0;i<10;i++){
this.count[i] = 1000;
}
}
public void trans(String name,int from,int to,int n) throws InterruptedException{
if(count[from]>n){
count[from]-=n;
System.out.print("");
count[to]+=n;
System.out.println(name+" : 用户"+from+"向用户"+to+"转入:"+n+" 目前总资金为:"+this.toString());
}
}
@Override
public String toString() {
// TODO Auto-generated method stub
int out = 0;
for(int i:count)
out+=i;
return out+"";
}
public int[] getCount() {
return count;
}

public void setCount(int[] count) {
this.count = count;
}
}
class Transable implements Runnable{


private Bank bank;
private int i;
public Transable(Bank bank,int i){
this.bank = bank;
this.i = i;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
bank.trans("线程"+i, RandomUtils.nextInt(10), RandomUtils.nextInt(10), RandomUtils.nextInt(1000));

} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

}

上述代码中会发生线程安全问题,对此有下面几个解决方案


//=============================================================。
解决方法一
public synchronized void trans(String name,int from,int to,int n) throws InterruptedException{
if(count[from]>n){
count[from]-=n;
System.out.print("");
count[to]+=n;
System.out.println(name+" : 用户"+from+"向用户"+to+"转入:"+n+" 目前总资金为:"+this.toString());
}
}
// 方法二
public void trans(String name,int from,int to,int n) throws InterruptedException{
lock.lock();
try{
while(count[from]>n){
count[from]-=n;
System.out.print("");
count[to]+=n;
System.out.println(name+" : 用户"+from+"向用户"+to+"转入:"+n+" 目前总资金为:"+this.toString());
}
}finally{
lock.unlock();
}
}
// 用条件对象改进 解决方法三
// 测试时,为试着将n改为 2*n 由于条件对象,照样可以运行,但是几秒之后发生死锁问题
public void trans(String name,int from,int to,int n) throws InterruptedException{
lock.lock();
try{
while(count[from]<n)
condition.await();
count[from]-=n;
System.out.print("");
count[to]+=n;
System.out.println(name+" : 用户"+from+"向用户"+to+"转入:"+n+" 目前总资金为:"+this.toString());
condition.signalAll();
}finally{
lock.unlock();
}
}
// 用synchronized 方法代替显式的锁,很方便,代码如下,与上面的代码功能一样 解决方法四
public synchronized void trans(String name,int from,int to,int n) throws InterruptedException{
while(count[from]<n)
wait();
count[from]-=n;
System.out.print("");
count[to]+=n;
System.out.println(name+" : 用户"+from+"向用户"+to+"转入:"+n+"目前总资金为:"+this.toString());
notifyAll();
}
// 前面3,4方法都有死锁。有一个解决方法是,给wait()一个时间限制,超时后,自动退出
public void trans(String name,int from,int to,int n) throws InterruptedException{
lock.lock();
try{
while(count[from]<n)
if(!condition.await(100, TimeUnit.MILLISECONDS)){
System.out.println("遇到死锁,此交易退出!!");
return;
}
count[from]-=n;
count[to]+=n;
System.out.println(name+" : 用户"+from+"向用户"+to+"转入:"+n+" 目前总资金为:"+this.toString());
condition.signalAll();
}finally{
lock.unlock();
}
}


6.阻塞队列

将线程安全等问题交给阻塞队列
public class BlockingQueueTest {


public static String src = "/usr/spring-framework-2.5.5_src";
public static void main(String[] args) {
BlockingQueue<File> queue = new ArrayBlockingQueue<File>(19999);
new Thread(new Find(queue, src)).start();
for(int i = 0;i<10;i++)
new Thread(new search(queue, "volatile")).start();
}
}


class Find implements Runnable{
private BlockingQueue<File> queue;
private String firstFileName;
public Find(BlockingQueue<File> queue, String firstFileName) {
super();
this.queue = queue;
this.firstFileName = firstFileName;
}
@Override
public void run() {
File file = new File(firstFileName);
try {
findFile(file);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

private void findFile(File file) throws InterruptedException{
if(file.isDirectory()){
File[] f = file.listFiles();
for(File tmp:f){
findFile(tmp);
}
}else{
if(!queue.offer(file, 1000, TimeUnit.MILLISECONDS))
System.out.println("添加失败");
}
}
}
class search implements Runnable{
private BlockingQueue<File> queue;
private String keyWords;
public search(BlockingQueue<File> queue, String keyWords) {
super();
this.queue = queue;
this.keyWords = keyWords;
}
@Override
public void run() {
// TODO Auto-generated method stub
boolean b = true;
try {
while(b){
File f = queue.poll(1000, TimeUnit.MILLISECONDS);
if(f==null){
b = false;
}else{
Scanner in = new Scanner(f);
int len = 0;
String tmp = "";
while(in.hasNext()){
len++;
tmp = in.nextLine();
if(tmp.contains(keyWords)){
System.out.println("文件名为:"+f.getName()+" 第"+len+"行 : ");
System.out.println(""+tmp);
}
}
}
queue.peek();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
}
}
}


7.Future  封装一个有返回值的一部运行任务,相当于有返回值的Runnable

//Callable 相当于一个带有参数的Runable


public class FutureTest {


public static String src = "/usr/spring-framework-2.5.5_src/src";
public static String key = "class";
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Find(new File(src), key));
new Thread(futureTask).start();
System.out.println("个数为:"+futureTask.get());
}
}
class Find implements Callable<Integer>{
private File firstFile;
private String key;
private int count;
public Find(File file,String key) {
super();
this.firstFile = file;
this.key = key;
}
private Integer findFile(File file) throws InterruptedException, ExecutionException{
List<Future<Integer>> list = new ArrayList<Future<Integer>>();
if(file.isDirectory()){
File[] f = file.listFiles();
for(File tmp:f){
if(tmp.isDirectory()){
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Find(tmp, key));
list.add(futureTask);
new Thread(futureTask).start();
}else{
if(search(tmp))
count++;
}
}
}else{
if(search(file))
count++;
}
for(Future<Integer> future:list){
count+=future.get();
}
return count;
}
public boolean search(File f) {
try {
if(f==null){
return false;
}else{
Scanner in = new Scanner(f);
String tmp = "";
while(in.hasNext()){
tmp = in.nextLine();
if(tmp.contains(key)){
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
}
return false;
}
@Override
public Integer call() throws Exception {
try {
return findFile(firstFile);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}



8,连接池

//简单使用连接池只需要将上面的代码修改下

public class ThreadPoolTest {


public static String src = "/usr/spring-framework-2.5.5_src/src";
public static String key = "class";
public static void main(String[] args) throws InterruptedException, ExecutionException {
//FutureTask<Integer> futureTask = new FutureTask<Integer>(new FindByPool(new File(src), key));
//new Thread(futureTask).start();
//System.out.println("个数为:"+futureTask.get());
ExecutorService service = Executors.newCachedThreadPool();
Future<Integer> future = service.submit(new FindByPool(new File(src), key,service));
System.out.println(future.get());
}
}
class FindByPool implements Callable<Integer>{
private File firstFile;
private String key;
private ExecutorService service;
private int count;
public FindByPool(File file, String key2, ExecutorService service) {
// TODO Auto-generated constructor stub
this.firstFile = file;
this.key = key2;
this.service = service;
}
private Integer findFile(File file) throws InterruptedException, ExecutionException{
List<Future<Integer>> list = new ArrayList<Future<Integer>>();
if(file.isDirectory()){
File[] f = file.listFiles();
for(File tmp:f){
if(tmp.isDirectory()){
FindByPool pool = new FindByPool(tmp,key,service);
list.add(service.submit(pool));
}else{
if(search(tmp))
count++;
}
}
}else{
if(search(file))
count++;
}
for(Future<Integer> future:list){
count+=future.get();
}
return count;
}
public boolean search(File f) {
try {
if(f==null){
return false;
}else{
Scanner in = new Scanner(f);
String tmp = "";
while(in.hasNext()){
tmp = in.nextLine();
if(tmp.contains(key)){
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
}
return false;
}
@Override
public Integer call() throws Exception {
try {
if(firstFile!=null)
return findFile(firstFile);
else return 0;
} catch (InterruptedException e) {
e.printStackTrace();
}
return 0;
}
}


上面就是简单使用Java多线程的部分,还有关于线程安全与高并发部分的内容没有写出来.尽快补上