文档章节

多线程-线程控制

skanda
 skanda
发布于 2016/11/13 22:14
字数 1667
阅读 10
收藏 1

 




// 通过实现Runnable接口来创建线程类
public class SecondThread implements Runnable
{
	private int i ;
	// run方法同样是线程执行体
	public void run()
	{
		for ( ; i < 100 ; i++ )
		{
			// 当线程类实现Runnable接口时,
			// 如果想获取当前线程,只能用Thread.currentThread()方法。
			System.out.println(Thread.currentThread().getName()
				+ "  " + i);
		}
	}

	public static void main(String[] args)
	{
		for (int i = 0; i < 100;  i++)
		{
			System.out.println(Thread.currentThread().getName()
				+ "  " + i);
			if (i == 20)
			{
				SecondThread st = new SecondThread();     // ①
				// 通过new Thread(target , name)方法创建新线程
				Thread thread = new Thread(st , "新线程1");
				thread.join();
			}
		}
	}
}

join()方法,当某个程序执行路中的调用其他线程的thread1.join()方法,该程序需要等待thread1执行结束再继续运行。

 

线程让步:yield,仅是将线程从执行状态转为就绪状态,不阻塞线程。在多cpu情况下,这个效果根本没用。所以yield也不是绝对能控制线程的方法

 

线程同步安全问题:

多个线程访问同一资源,会造成线程错误: 由此衍生出几种解决方案:

1,synchronized:加锁-修改-释放锁;

2,lock ReentrantLock

 ReentrantLock lock = new ReentrantLock();

lock.lock();

lock.unlock();

eg 银行取款问题:

1,用户输入取款金额;

2,系统判断账号余额是否大于取款金额;

3, 如果余额大于取款金额,取款成功,如果余额小于取款金额,取款失败;

银行账户类 account.java


public class Account {
	
	private String accountNo;
	private double balance;
	public Account(String accountNo, double balance) {
		super();
		this.accountNo = accountNo;
		this.balance = balance;
	}
	public String getAccountNo() {
		return accountNo;
	}
	public void setAccountNo(String accountNo) {
		this.accountNo = accountNo;
	}
	public double getBalance() {
		return balance;
	}
	public void setBalance(double balance) {
		this.balance = balance;
	}
	
	
}

 

取款线程类:


public class DrawThread extends Thread{

	private Account account;
	private double drawAmount;
	
	
	public Account getAccount() {
		return account;
	}

	public void setAccount(Account account) {
		this.account = account;
	}

	public double getDrawAmount() {
		return drawAmount;
	}

	public void setDrawAmount(double drawAmount) {
		this.drawAmount = drawAmount;
	}

	public DrawThread(Account account, double drawAmount) {
		super();
		this.account = account;
		this.drawAmount = drawAmount;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		
		if(account.getBalance()>=drawAmount)
		{
			System.out.println("取钱成功!吐出钞票"+drawAmount);
			
			// 修改余额
			account.setBalance(account.getBalance()-drawAmount);
			System.out.println("余额:"+account.getBalance());
		}
		else {
			System.out.println("余额不足!");
		}
		
		
		
		
		
	}






	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		
	}

}

取款main:

import java.awt.List;
import java.io.Console;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;

/**
 * 
 */

/**
 * @author lrh
 *
 */
public class T {

	/**
	 * @param args
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		
		Account account = new Account("123", 1000);
		new DrawThread(account, 800).start();
		new DrawThread(account, 800).start();
		
	}

}

 

多线程并发访问,会造成取款错误:

取钱成功!吐出钞票800.0
余额:200.0
取钱成功!吐出钞票800.0
余额:-600.0

因此,引入同步代码块这个概念:


public class DrawThread extends Thread{

	private Account account;
	private double drawAmount;
	
	
	public Account getAccount() {
		return account;
	}

	public void setAccount(Account account) {
		this.account = account;
	}

	public double getDrawAmount() {
		return drawAmount;
	}

	public void setDrawAmount(double drawAmount) {
		this.drawAmount = drawAmount;
	}

	public DrawThread(Account account, double drawAmount) {
		super();
		this.account = account;
		this.drawAmount = drawAmount;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		synchronized (account) 
		{
			if(account.getBalance()>=drawAmount)
			{
				System.out.println("取钱成功!吐出钞票"+drawAmount);
				
				// 修改余额
				account.setBalance(account.getBalance()-drawAmount);
				System.out.println("余额:"+account.getBalance());
			}
			else {
				System.out.println("余额不足!");
			}
		}
		
		
		
		
		
	}






	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		
	}

}

synchronized 保证只有一个线程多共享资源account进行访问

运行结果:

取钱成功!吐出钞票800.0
余额:200.0
余额不足!

 

ThreadLocal:线程局部变量 ,为每一个使用该变量的线程都提供一个变量值得副本;


public class Account {

	private ThreadLocal<String> name = new ThreadLocal<>();

	public Account(String Str) 
	{
		super();
		this.name.set(Str);
		System.out.println("----"+this.name.get());
	}

	public String getName() {
		return name.get();
	}

	public void setName(String str) {
		this.name.set(str);
	}
	
	
}

public class MyTest extends Thread {

	private Account account;
	public MyTest(Account account,String name) 
	{
		super(name);
		this.account=account;
	}
	
	public void run()
	{
		for(int i =0;i<10;i++)
		{
			if(i==6)
			{
				account.setName(getName());
			}
			System.out.println(account.getName()+"账号的i值:"+i);
			
		}
	}
	
	
	
}

public class ThreadLocalTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Account at = new Account("初始名");
		new MyTest(at, "线程甲").start();
		new MyTest(at, "线程乙").start();
	}

}

两个线程各有一个线程局部变量.

result:

----初始名
null账号的i值:0
null账号的i值:1
null账号的i值:0
null账号的i值:1
null账号的i值:2
null账号的i值:2
null账号的i值:3
null账号的i值:4
null账号的i值:5
null账号的i值:3
null账号的i值:4
null账号的i值:5
线程甲账号的i值:6
线程甲账号的i值:7
线程甲账号的i值:8
线程甲账号的i值:9
线程乙账号的i值:6
线程乙账号的i值:7
线程乙账号的i值:8
线程乙账号的i值:9
 

线程同步锁lock.

lock比synchroniezed方法和synchronized代码块更灵活,所以个人还是喜欢用这个。

下面是一个本地例子:

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;


public class Test implements Runnable{

	private final ReentrantLock lock = new ReentrantLock();
	/*
	 * 加锁前打印
	 * */
	public void run()
	{
		//加锁前打印
		System.out.println(new Date()+Thread.currentThread().getName() +" 准备进入线程");
		lock.lock();
		//锁内延时
		try {
			Thread.sleep(2222);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//锁内打印
		System.out.println(new Date()+Thread.currentThread().getName()+" 进入线程成功");
		lock.unlock();
		//解锁后打印
		System.out.println(new Date()+Thread.currentThread().getName()+" 离开线程成功");
		
	}
	/**
	 * @param args
	 * @throws InterruptedException 
	 * @throws IOException 
	 * 创建两个线程,并行执行
	 */
	public static void main(String[] args) throws InterruptedException{
		// TODO Auto-generated method stub
		Test t1=  new Test();
		new Thread(t1).start();
		new Thread(t1).start();
		//Thread.sleep(9999);
		
	}

}

运行结果:

Sat May 06 17:14:31 CST 2017Thread-0 准备进入线程
Sat May 06 17:14:31 CST 2017Thread-1 准备进入线程
Sat May 06 17:14:33 CST 2017Thread-0 进入线程成功
Sat May 06 17:14:33 CST 2017Thread-0 离开线程成功
Sat May 06 17:14:35 CST 2017Thread-1 进入线程成功
Sat May 06 17:14:35 CST 2017Thread-1 离开线程成功

重点在时间,且二者共用一个线程类

加锁后1号线程无法进入,被锁在外头了。这个控制的很好。

稍作修改:

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;


public class Test implements Runnable{

	private final ReentrantLock lock = new ReentrantLock();
	/*
	 * 加锁前打印
	 * */
	public void run()
	{
		//加锁前打印
		System.out.println(new Date()+Thread.currentThread().getName() +" 准备进入线程");
		lock.lock();
		
		//锁内打印
		System.out.println(new Date()+Thread.currentThread().getName()+" 进入线程成功");
		//锁内延时
		try {
			Thread.sleep(2222);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		lock.unlock();
		//解锁后打印
		System.out.println(new Date()+Thread.currentThread().getName()+" 离开线程成功");
		
	}
	/**
	 * @param args
	 * @throws InterruptedException 
	 * @throws IOException 
	 * 创建两个线程,并行执行
	 */
	public static void main(String[] args) throws InterruptedException{
		// TODO Auto-generated method stub
		Test t1=  new Test();
		Test t2=  new Test();
		new Thread(t1).start();
		new Thread(t2).start();
		//Thread.sleep(9999);
		
	}

}

 

重点在main函数里面的:

Test t1=  new Test();
        Test t2=  new Test();
        new Thread(t1).start();
        new Thread(t2).start();

运行结果其实就是两个对象的两把锁了,这点尤其要注意。

所以运行结果如下:

Sat May 06 17:17:39 CST 2017Thread-0 准备进入线程
Sat May 06 17:17:39 CST 2017Thread-0 进入线程成功
Sat May 06 17:17:39 CST 2017Thread-1 准备进入线程 --两者都进入锁,因为其实是两把锁
Sat May 06 17:17:39 CST 2017Thread-1 进入线程成功
Sat May 06 17:17:41 CST 2017Thread-0 离开线程成功
Sat May 06 17:17:41 CST 2017Thread-1 离开线程成功

 

线程通信:使用BlockingQueue控制线程通信

© 著作权归作者所有

skanda
粉丝 11
博文 103
码字总数 59071
作品 0
厦门
私信 提问
ios的线程和同步异步操作

ios的线程和同步异步操作 ios的线程和同步异步操作 ios的多线程,同步异步操作,都是我们日常的开发中经常会遇到的问题,本文把常见的ios线程,同步异步的操作进行了整理。 代码下载: 我博客...

lewis-180
2015/12/08
57
0
day23-----------多线程(传智视频)

多线程概述 package cn.itcast_01;/* * 进程: * 正在运行的程序,是系统进行资源分配和调用的独立单位。 * 每一个进程都有它自己的内存空间和系统资源。 * 线程: * 是进程中的单个顺序控制...

萧小蚁
2016/02/23
60
0
精选30道Java多线程面试题

1、线程和进程的区别 2、实现线程有哪几种方式? 3、线程有哪几种状态?它们之间如何流转的? 4、线程中的start()和run()方法有什么区别? 5、怎么终止一个线程?如何优雅地终止线程? 6、T...

java技术栈
2017/08/13
0
0
ios 重温多线程 总结

1>无论使用哪种方法进行多线程开发,每个线程启动后并不一定立即执行相应的操作,具体什么时候由系统调度(CPU空闲时就会执行)。 2>更新UI应该在主线程(UI线程)中进行,并且推荐使用同步调...

那条鱼
2016/03/17
22
0
C#多线程学习(一) 多线程的相关概念

摘要:关于线程的相关概念 本系列文章导航 C#多线程学习(一) 多线程的相关概念 C#多线程学习(二) 如何操纵一个线程 C#多线程学习(三) 生产者和消费者 C#多线程学习(四) 多线程的自动管理(线程...

Yamazaki
2012/03/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

axios 使用步骤很简单,首先在前端项目中,引入 axios:

  前端网络访问,主流方案就是 Ajax,Vue 也不例外,在 Vue2.0 之前,网络访问较多的采用 vue-resources,Vue2.0 之后,官方不再建议使用 vue-resources ,这个项目本身也停止维护,目前建...

SEOwhywhy
10分钟前
0
0
c++ 创建对象的三种方法

c++有三种方法创建对象 结合代码来看 1 #include <iostream> 2 using namespace std; 3 class Test { 4 5 private: 6 public: 7 add() 8 { 9 ......

天王盖地虎626
24分钟前
0
0
ant 中的fileset include等拷贝

拷贝一个目录到指定目录下 例:<copy todir="${basedir}/new"> <fileset dir="${basedir}/old"> <include name="appgen" /> <include name="appgen/" /> <include name=appgen/**" /> <incl......

shzwork
30分钟前
2
0
react-jianshu项目的创建

创建项目 1、github上创建仓库react-jianshu 2、将项目克隆到本地git clone git@github.com:startjcu/react-jianshu.git 3、在当前目录(项目目录的上级目录)下执行create-react-app react-...

星闪海洋
39分钟前
2
0
OSChina 周二乱弹 —— 小哥哥,你可以教我写代码吗

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @nnnm: 生活大爆炸,结束了,这部陪伴了漫长时间的情景喜剧,最终是以诺贝尔奖和大团圆收尾的。虽然,不算精彩,但也是温馨。而少年谢尔顿的...

小小编辑
今天
480
12

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部