Thread相关:
线程相关方法
1. java启动时至少有两个线程,一、是主线程;二、垃圾回收线程
2. 线程获取当前线程名方法:Thread.currentThread().getName();
3. 设置线程的名称:MyThread t1 = new MyThread(); t1.setName("MyThread1");
4. 设置线程的级别,MyThread t3 = new MyThread();t3.setName("MyThread3");
t3.setPriority(10);级别:1-10;
5.守护线程ThreadDaemon t1 = new ThreadDaemon();
t1.setName("Thread");
t1.setDaemon(true);//守护线程
t1.start();
6.加入线程:ThreadJoin t1 = new ThreadJoin();
t1.setName("Thread");
t1.start();
t1.join();//执行该条语句的线程,会加入到t1线程后面,t1结束后采取执行自己的线程
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"-"+i);
}
7. Thread.sleep(1000);在指定的毫秒内,线程休眠,休眠期间会放弃cpu的资源,但是不会放弃监视器的资源;
8.线程停止方法:t1.interrupt();
9.通过实现Runnable接口,从而实现线程,首先创建一个MyRunnable类实现Runnable接口,然后创建新的线程,将接口放入线程中,MyRunnable r1 = new MyRunnable();
Thread t1 = new Thread(r1,"Thread");
t1.start();
10.线程阻塞三个必要条件:1.是否是多线程环境;2.是否是共享数据;3.是否是多条语句操作共享数据;
11.买票问题:如果单纯使用如下方式:
public class SellTicket implements Runnable {
private int tickets = 100;
public void run() {
while(tickets>0){
System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"票");
}
}
}
package tm.change_06;
public class SellTicketDemo {
public static void main(String[] args) {
SellTicket r = new SellTicket();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
Thread t3 = new Thread(r);
t1.setName("张飞");
t2.setName("关羽");
t3.setName("刘备");
t1.start();
t3.start();
t2.start();
}
}
这样很可能出现负数票和重复票的情形;
为了避免出现重复票和负数票的情形,添加synchronized进行包裹;
12. ArrayList list1 = new ArrayList();//线程不安全,是允许线程并发操作,优点是速度块
List list2 = (List) Collections.synchronizedList(list1);//线程安全的
//线程安全
StringBuffer sb = new StringBuffer();
Vector v = new Vector();
13.使用Lock方法锁住线程:
使用方式,1.声明Lock, private Lock lock=new ReentrantLock();2.加锁:lock.lock();,3.解锁:lock.unlock();
14.线程同步:
弊端:1.效率低,2.容易产生死锁;原因在于两个或两个以上的线程在争夺资源的时候,发生了一种互相等待的现象;
15.Object类中提供三种方法:
1.wait()等待,及时让出CPU,也让出监视器资源
2.notify()唤醒第一个线程;
3.notifyAll()唤醒所有等待的线程;
加油相关问题:
1. 创建JYZ类,声明汽油的数量,建立flag来表明油够的状态true或false的状态,创建flag的get,set方法;分别创建同步的加油和减油的操作;
2. 创建Car类,实现Runnable接口,在类中声明加油站对象,并在构造函数中体现;
3. 创建Worker类,实现Runnable接口,在类中声明加油站对象,并在构造函数中体现;
JYZ类相关代码:
private Integer qycount = 0;//汽油的数量
private boolean flag = false;//false 油不够了
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
//向加油站中注入汽油
public synchronized void plusOil(int c){
if(this.flag){ //加油站中的油是够的,就需要等待,释放掉CPU资源和监视器
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//否则加油c升
this.qycount += c;
System.out.println(Thread.currentThread().getName()+"增加了"+c+"升汽油");
//加好后设置油满了,通知所有
this.setFlag(true);
this.notifyAll();
}
//减少汽油
public synchronized void subtractOil(int c){
//因可能会有多辆车进行加油,减少可能会很多,所以在当前的汽油数量少于乘客需要加油的数量时,那么需要让线程进行等待,设置油的状态是未满,否则在循环中减少汽油的数量
while(this.qycount<c){//汽油不够
System.out.println(Thread.currentThread().getName()+"加"+c+"升汽油,等待中......");
this.setFlag(false);
try {
this.notifyAll();
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.qycount-=c;
System.out.println(Thread.currentThread().getName()+"加"+c+"升汽油");
}
}
Car类相关操作:
声明JYZ类,初始化一次性加油的数量,在Car的构造函数中,设置加油的数量,因为是随机使用Random函数;在run方法中,加油站的油减少
public class Car implements Runnable {
private JYZ jyz;
private Integer count=0;//一次加油的数量
public Car(JYZ j){
this.jyz = j;
Random random = new Random();
this.count = random.nextInt(10)+1;
}
@Override
public void run() {
this.jyz.subtractOil(this.count);
}
}
Worker类:
如果油没有满的情况下,jyz的油会继续增加20;
public class Worker implements Runnable {
private JYZ jyz;
public Worker(JYZ j){
this.jyz = j;
}
@Override
public void run() {
while(true){
this.jyz.plusOil(20);
}
}
}
如果是所有的车一起来,创建加油站的实例对象,创建Worker实例对象,创建线程,遍历来的车,如果是新的车,这样就传入新的车,每辆车开启线程,当循环后,开启主线程
public static void main(String[] args) {
JYZ jyz = new JYZ();
Worker worker = new Worker(jyz);
Thread t1 = new Thread(worker,"工作人员");
for(int i=0;i<10;i++){
Car car = new Car(jyz);
Thread t = new Thread(car,"汽车"+i);
t.start();
}
t1.start();
}
如果要按照顺序来加油,
JYZ jyz = new JYZ();
Worker worker = new Worker(jyz);
Thread t1 = new Thread(worker,"工作人员");
t1.start();
for(int i=0;i<10;i++){
Car car = new Car(jyz);
Thread t = new Thread(car,"汽车"+i);
t.start();
t.join();
}
线程组:
1.创建MyRunnable接口实现Runable接口
2.创建主类,在main方法中创建线程组
1)创建ThreadGroup对象,在对象中有名称;
2)分别创建两个线程,指明名称;
3) 设置线程组级别
4)设置守护线程
public static void main(String[] args) {
// System.out.println(Thread.currentThread());
// Thread t1 = new Thread(new MyRunnable());
// System.out.println(t1);
method2();
}
public static void method2(){
ThreadGroup tg = new ThreadGroup("新的线程组");
Thread t1 = new Thread(tg,new MyRunnable(),"张三");
Thread t2 = new Thread(tg,new MyRunnable(),"李四");
tg.setMaxPriority(10);
tg.setDaemon(true);
System.out.println(t1);
System.out.println(t2);
}
线程池:
定义:线程池是线程的容器,使用线程时,从线程池中获得线程,线程不用时,将线程还给线程池,避免反复创建线程和结束线程;
思路:
1.创建线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
2.让线程池执行任务
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
3.结束线程池
pool.shutdown();/
4.结束线程池:1)组织新任务的加入;2)关闭线程池,试图停止所有正在执行的活动任务;
pool.shutdownNow();
第二种思路:
1.创建线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
2.让线程池执行任务
Future<Integer> f1=pool.submit(new MyCallable(100000000));
Future<Integer> f2=pool.submit(new MyCallable(200000000));
Integer i1 = f1.get();
Integer i2 = f2.get();
System.out.println(i1);
System.out.println(i2);
3.结束线程
pool.shutdown();//阻止新任务的加入
pool.shutdownNow();//关闭线程池,并或的为执行任务列表
System.out.println("完成");
两种方法不同点:
1.Future<?> submit(Runnable task)
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
2.Future<T> submit(Callable<T> task)
提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
线程的多种打开实现方式:
1.继承thread实现多线程:
new Thread(){
public void run(){
System.out.println("thread1");
}
}.start();
2.实现了Runnable接口来实现多线程
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("thread2");
}
}).start();
3.使用多重run方法,不过结果只是thread4
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("thread3");
}
}){
public void run(){
System.out.println("thread4");
}
}.start();
使用ThreadLocal来实现多线程操作,并保证同一个Connection,进行事务处理;
一、创建AppContext类
1)创建单例AppContext单例对象;
2)声明ThreadLocal类对象;
3)使用ThreadLocal绑定连接,获取绑定连接,解绑连接;
代码:
public class AppContext {
// 类变量
public static AppContext instance = new AppContext();
//线程池子
private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
private AppContext() {
}
public static AppContext getInstance() {
return instance;
}
/**
* 绑定
* @param conn
*/
public void bind(Integer conn){
threadLocal.set(conn);
}
/**
* 获取绑定对象
*/
public Integer get(){
return threadLocal.get();
}
/**
* 解除绑定
*/
public void unbind(){
threadLocal.remove();
}
}