java线程基础

在java中,每个任务都是Runnable接口的一个实例,也可以成为运行对象。线程上本质上讲就是便于任务执行的对象。

任务就是对象。

创建一个线程1:实现Runnable接口

  • 创建一个任务
TaskClass task = new TaskClass(...);
  • 任务类必须在线程中执行
Thread thread = new Thread(task);
  • 然后调用start方法告诉虚拟机该线程准备运行
thread.start();

TaskClass是自己创建的,完成要完成的任务。”=”左边的Taskclass可以换成Runnable。TaskClass实现Runnable接口。

创建一个线程2:继承Thread类

  • 创建Thread类扩展对象
TaskClass task = new TaskClass(...);
  • 然后调用start方法告诉虚拟机该线程准备运行
thread.start();

这里的TaskClass和上面的区别是:这里是继承了Thread类,其余都一样。Thread类本身实现了Runnable接口。

任务类(这里是实现Runnable接口的任务类)

  • 任务类比普通类多了run方法。具体如下:
public void run(...) {
...
}
  • 任务类要实现Runnable接口
class TaskClass implements Runnable {
...
}

直接调用任务类中run方法,只是在同一个线程中执行该方法,而没有新的线程被启动。

Thread 类

  • Thread类包含stop(),suspend()和resume()方法,普遍认为不安全,不使用
  • 代替stop()方法,可以给Thread类赋值null,来表明停止。
  • yield()的方法为其他线程临时让出cpu时间
  • sleep(long mills)
    设置休眠,让出cpu时间,单位毫秒。
  • java线程优先级1-10.
    • MIN_PRIORITY = 1
    • NORM_PRIORITY = 5
    • MAX_PRIORITY = 10

    如果总有一个较高的优先级在运行,或者相同的优先级线程不退出,那么这个线程可能永远没有运行机会。这种情况称为资源竞争或缺乏状态(contention or starvation)。为了避免竞争,高优先级线程必须定时调用yield方法或sleep方法。
线程池
  • 线程池是管理并发执行任务的理想方法。Java提供Executor接口来执行线程池中的任务。ExecutorService来管理和控制任务。

执行创建3个线程来并发执行3个任务

ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.execute(printA);
        executor.execute(thread1);
        executor.execute(print100);
        executor.shutdown();
  • Executors.newFixedThreadPool(3):

    将3改为1,这3个任务将顺序执行

    改为Executors.newCachedThreadPool(),则为每>>个等待的任务创建一个新线程,即来一个任务,创建一个线程,所以,任务会并发的执行。
    shutdown通知执行器关闭,不能接收新任务。但现有任务将继续执行直到完成。


线程同步
为避免竞争状态,应该防止多个线程同时进入程序的某一特定部分,程序中的这部分称为临界区(critical region)。 解决办法 - 添加关键字synchroized,下面两种方法都行。
 public synchronized void xMethod() {
    //thod body
    }
 public void xMethod() {
    synchronized(this) {
        //method body
       }
   }
同步(synhronized)方法在执行之前都隐式的加了锁。
  • (显式)加锁。
    • 实例方法:给调用该方法的对象加锁
    • 静态方法:要给这个类加锁

private static Account account = new Account();
lock.lock();
try {
            ...
            }
            catch (InterruptedException ex) {

            }
            finally {
                lock.unlock();
            }
线程间协作
  • await():让当前的线程都处于等待状态,直到条件发生
  • signal():唤醒一个等待的线程
  • signalAll():唤醒所有等待的线程
private static Condition newDeposit = lock.newCondition();
newDeposit.await();
newDeposit.signalAll();
java的内置监视器(java5 之前的内容) 一旦一个线程锁住对象,该对象就成为监视器。 用法:在方法或块上使用关键字synchronized. wait(),notify(),或notifyAll()方法在接收对象的同步方法或同步块调用。
synchronized (anObject) {
...
anObject.wait();
...
}

synchronized (anObject) {
...
anObject.notify();
...
}
阻塞队列(blocking queue) 阻塞队列在试图向一个满队列添加元素或者空队列删除元素时,会导致线程阻塞。 java支持3个具体的阻塞队列
  • ArrayBlockingQueue :可选的容量ArrayBlockingQueue(capacity:int)或者指定公平性ArrayBlockingQueue(capacity:int,fair:boolea)
  • LinkedBlockingQueue 可以创建不受限的LinkedBlockingQueue()或者受限的队列LinkedBlockingQueue(capacity:int)
  • PriorityBlockingQueue可以创建不受限的PriorityBlockingQueue()或者受限的队列PriorityBlockingQueue(capacity:int)
  • put 向尾添加元素
  • take 向头删除元素

信号量

信号量可以用来限制访问共享资源的线程数,在访问资源之前,线程必须从信号量获取许可。在访问完资源之后,这个线程必须将资源返回给信号量。

  • 创建许可
private static Semephore semaphore = new Semaphore(n);
  • 从信号量获取许可(不可用,等待)
semaphore.acquire();
  • 释放对信号源的许可
semaphore.release();

感觉信号量和锁是类似的,获得许可相当于上锁,上锁只允许一个资源使用,获得许可后,只允许有限的线程进行访问资源。

避免死锁

有时两个或者多个线程需要在几个共享的对象上获取锁,这可能会导致死锁。

资源排序(resource ordering)可以轻易避免死锁的发生。假如线程要想对资源2上锁,必须要先获取资源1的锁。

线程的状态

  • 新建(New):创建新的线程
  • 就绪(Ready):start() 或超时(cpu分配的时间用完)或yield
  • 运行(Running):run()
  • 阻塞(Blocked):join(等待目标结束中。。),sleep(等待超时中。。。),wait()等待通知中。。当阻塞的行为不起作用时,线程就被重新激活进入就绪状态。
  • 结束(finished):run()完成

就绪和运行线程是激活的。新建,阻塞和结束线程没被激活。

同步集合

Java集合框架中的类不是线程安全的,也就是说,如果它们同时被多个线程访问和更新,它们的内容可能被破坏。

java有6中静态方法将集合转换为同步版本,称为同步包装类。

  • syncoronizedCollection(c:Collection):Collection
  • syncoronizedList(list:List):List
  • syncoronizedMap(map:Map):Map
  • syncoronizedSet(set:Set):Set 规则集
  • syncoronizedSortedMap(s:SortedMap):SortedMap 有序图
  • syncoronizedSortedSet(s:SortedSet):SortedSet 有序规则集

java.util.Vector java.util.Stack java.util.HashTable中的方法已经被同步,这些都是java中的旧类。java.util.ArrayList,java.util.LinkedList,java.util.Map是对应的新类。

同步包装类都是线程安全的,但是迭代器具有快速失败的特性:如果整个集合使用一个迭代器,迭代器通常抛出异常。为了避免这个错误,需要创建一个同步集合对象,并且在遍历它时,获取对象上的锁。

Set hashSet = Collections.synchronizedSet(new HshSet());
synchronized (hashSet) {
Iterator iterator = hashSet.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值