package threadpackage; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.PrintWriter; import java.util.Random; /* 一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。 要求启动10个线程,两两一组,分为5组。 每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中, 需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。 同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”. */ /** * 分析:可以将10000个数分成5份,每一份(2000个数)对应一组,即两个线程,来分别输出这一份的奇数和偶数, * 同时声明一个共享变量,用于统计当前所有线程输出的个数,反映记录的输出进度 */ public class PrintByThread { public static void main(String[] args) { try { //创建一个包含10000数字的输入文件 PrintWriter pw=new PrintWriter(new FileWriter(new File("input.txt")),true); Random random=new Random(); for (int i = 0; i < 10000; i++) { pw.print(Math.abs(random.nextInt())%100+","); } pw.flush(); pw.close(); //读取文件中的数字,分5次读取,每次读取2000个 BufferedReader reader=new BufferedReader(new FileReader("input.txt")); String str=reader.readLine(); reader.close(); String[] strs=str.split(",");//将一行字符串全部解析为10000个数字 int j=0;//10000个数的索引计数 for (int i = 0; i < 5; i++) { int records[]=new int[2000]; for (int k = 0; k < 2000; k++) { records[k]=Integer.parseInt(strs[j]); j++; } //定义输出文件 PrintWriter writer =new PrintWriter(new FileWriter(new File("output"+i+".txt")),true); //定义实现的方法 ThreadGroup group=new ThreadGroup(records, writer); //开启一对儿线程 new Thread(group).start(); new Thread(group).start(); } } catch (Exception e) { // TODO: handle exception } } }
package threadpackage; import java.io.PrintWriter; class ThreadGroup implements Runnable{ //所有类对象共享的同一个计数器count,记录总共输出的记录总数 private static int count=0; //所有的ThreadGroup类对象共享一个锁,用于count变量的同步,任何一个线程需要修改count变量,必须取得该锁 private static Object lock=new Object(); public static final int EVEN=0;//代表偶数 public static final int ODD=1;//代表奇数 //*********以上静态变量,属于整个类所有*********** private int type; private int records[]; private PrintWriter writer;//每组共享一个writer,输出到同一个文件 private int oddPoint=0;//记录每次打印奇数的起始位置 private int evenPoint=0;//记录每次打印偶数的起始位置 public ThreadGroup(int[] records,PrintWriter writer){ this.records=records; this.writer=writer; this.type=EVEN; } //线程方法实现 public void run() { while(print()); } private synchronized boolean print(){ for(int i=0;i<10;){ //如果奇数和偶数都打印完成以后,就直接停止打印循环,等待该线程自己结束 if (oddPoint>=records.length&&evenPoint>=records.length) { notifyAll(); return false; } //如果该线程该打印奇数,但奇数已经打印晚了,就直接停止本次10个数的打印, //同理偶数,等下次切换打印类型后,再开始打印另外一种类型 if ((oddPoint>=records.length&&type==ODD)||(evenPoint>=records.length&&type==EVEN)) { break; } //判断开始打印偶数 if (type==EVEN) { if (records[evenPoint]%2==0) { i++; writer.print(records[evenPoint]+","); writer.flush(); //锁定全局变量方便线程输出后计数 synchronized (lock) { count++; if (count%1000==0) { System.out.println("当前完成数量:"+count); if (count==10000) { System.out.println("Done!"); } } } } //无论是否是偶数,打印成功一个后,偶数的起始位置都要后移 evenPoint++; }else { //打印奇数 if (records[oddPoint]%2==1) { i++; writer.print(records[oddPoint]+","); writer.flush(); //锁定全局变量方便线程输出后计数 synchronized (lock) { count++; if (count%1000==0) { System.out.println("当前完成数量:"+count); if (count==10000) { System.out.println("Done!"); } } } } //无论是否是奇数,打印成功一个后,偶数的起始位置都要后移 oddPoint++; } } type=~type;//切换打印类型 notifyAll();//一组中的任一线程打印完后唤醒另一个线程 try { wait();//释放锁进入等待状态,等待另一线程打印 } catch (Exception e) { // TODO: handle exception } return false; } }
package interviewquestion;
import java.io.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class WorkQueue {
private ConcurrentLinkedQueue oddQueue = new ConcurrentLinkedQueue();
private ConcurrentLinkedQueue evenQueue = new ConcurrentLinkedQueue();
private AtomicBoolean isClose = new AtomicBoolean(false);
private AtomicInteger workCount = new AtomicInteger(0);
private ExecutorService service;
private CountDownLatch latch;
private PrintWriter writer;
private int threads;
private int targets = 10000;
public WorkQueue(ExecutorService service, int threads, CountDownLatch latch) {
this.service = service;
this.threads = threads;
this.latch = latch;
}
public void doWork() throws IOException {
service.execute(new Producer());
writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream("result.txt")));
for(int i = 0; i < threads; i++) {
Worker evenWorker = new Worker(evenQueue, true);
Worker oddWorker = new Worker(oddQueue, false).setCoWorker(evenWorker);
service.execute(evenWorker);
service.execute(oddWorker);
}
/*用于模拟输入
for(int i = 1; i <= targets; i++) {
if(i % 2 == 0) {
evenQueue.add(i);
} else {
oddQueue.add(i);
}
}*/
}
private void writeToFile(Integer integer) throws IOException {
writer.print(integer.intValue() + "\n");
int current = workCount.incrementAndGet();
if(current % 1000 == 0) {
System.out.println("当前完成数:" + current);
}
if(current >= targets) {
isClose.set(true);
System.out.println("done");
}
}
public void close() {
writer.flush();
writer.close();
service.shutdown();
}
private class Worker implements Runnable {
private AtomicBoolean doWork;
private Worker coWorker;
private ConcurrentLinkedQueue works;
public Worker(ConcurrentLinkedQueue works, boolean doWork) {
this.doWork = new AtomicBoolean(doWork);
this.works = works;
}
public boolean isClose() {
return isClose.get() && works.isEmpty();
}
public Worker setCoWorker(Worker coWorker) {
this.coWorker = coWorker;
coWorker.coWorker = this;
return this;
} [@Override](/profile/992988) public void run() {
try {
while(!isClose()) {
if(doWork.get()) {
for(int count = 0; count < 10 && !isClose();) {
Integer num = works.poll();
if(num != null) {
writeToFile(num);
count++;
}
}
doWork.set(false);
coWorker.doWork.set(true);
}
}
} catch (Exception e) {} finally {
latch.countDown();
}
}
}
public class Producer implements Runnable { [@Override](/profile/992988) public void run() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("input.txt"));
String line = reader.readLine();
int temp;
for(String string : line.split(" ")) {
temp = Integer.parseInt(string);
if(temp % 2 == 0) {
evenQueue.add(temp);
} else {
oddQueue.add(temp);
}
}
} catch (Exception e) {}
finally {
if(reader != null) {
try {
reader.close();
} catch (Exception e) {}
}
}
}
}
public static void main(String[] args) {
int threads = 10;
CountDownLatch latch = new CountDownLatch(threads);
WorkQueue workQueue = null;
try {
ExecutorService executor = Executors.newFixedThreadPool(threads);
workQueue = new WorkQueue(executor, threads, latch);
workQueue.doWork();
latch.await();
} catch (Exception e) {}
finally {
if(workQueue != null) {
workQueue.close();
}
}
}
}
package first; import java.io.File; import java.io.PrintWriter; import java.net.URL; import java.util.ArrayDeque; import java.util.Queue; import java.util.Scanner; public class Solve { public static void main(String[] args) throws Exception { URL url = CreateData.class.getResource("/data.txt"); Scanner scanner = new Scanner(new File(url.toURI())); for (int i = 0; i < 10000; i++) { int data = Integer.parseInt(scanner.nextLine()); if (data % 2 == 0) { Common.ou.add(data); } else { Common.ji.add(data); } } scanner.close(); Thread[] threads =new Thread[10]; for (int i = 0; i < 5; i++) { PrintWriter pw = new PrintWriter(new File("./data"+i+".txt")); Common common=new Common(); threads[i*2] = new Thread(new WriterJi(pw,common)); threads[i*2+1] = new Thread(new WriterOu(pw,common)); } for (Thread thread : threads) { thread.start(); } } } class Common { //每组打印线程奇偶打印标志 public volatile boolean isJi = false; private static int count = 0; public static Queue<Integer> ji = new ArrayDeque<>(10000); public static Queue<Integer> ou = new ArrayDeque<>(10000); public static synchronized Integer jiGet() { inc(); if (!ji.isEmpty()) { return ji.poll(); } else { return null; } } public static synchronized Integer ouGet() { inc(); if (!ou.isEmpty()) { return ou.poll(); } else { return null; } } public static synchronized void inc() { if(++count %1000 ==0) { System.out.println(count); } if(count == 10000) { System.out.println("Done"); } } } class WriterJi implements Runnable { public PrintWriter pw; private int count = 0; private Common common; public WriterJi(PrintWriter pw,Common common) { this.pw = pw; this.common= common; } @Override public void run() { while (!Common.ji.isEmpty() || !Common.ou.isEmpty()) { if (common.isJi == true) { while (++count <= 10) { Integer data =Common.jiGet(); if(data != null) { pw.println(data); } else { break; } } pw.flush(); count = 0; common.isJi = false; } } } } class WriterOu implements Runnable { private PrintWriter pw; private int count = 0; private Common common; public WriterOu(PrintWriter pw,Common common) { this.pw = pw; this.common =common; } @Override public void run() { while (!Common.ji.isEmpty() || !Common.ou.isEmpty()) { if (common.isJi == false) { while (++count <= 10) { Integer data =Common.ouGet(); if(data != null) { pw.println(data); } else { break; } } pw.flush(); count = 0; common.isJi = true; } } } }
import java.io.*;
import java.util.Random;
public class multiThreadPrint {
private static final String path = "E:\\JavaBook\\MyprojectTouTiao\\MyAlgorithms\\fileprint\\";
//一个文件中有10000个数,
// 用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。
// 要求启动10个线程,两两一组,分为5组。
// 每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,
// 需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。
// 同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,
// 并在所有线程结束后,在控制台打印”Done”.
public static void main(String[]args)
{
try {
PrintWriter pw = new PrintWriter(new FileWriter(new File(path+"input.txt")),true);
Random random = new Random();
for(int i =0;i<10000;i++)
{
pw.print(Math.abs(random.nextInt())%100+" ");
}
pw.flush();
pw.close(); //输出10000个数到文件中。
BufferedReader reader = new BufferedReader(new FileReader(path+"input.txt"));
String str = reader.readLine();
reader.close();
String []strs = str.split(" ");
int j =0;
for(int i=0;i<5;i++)
{
int []records = new int [2000];
for(int k=0;k<2000;k++)
{
records[k] = Integer.parseInt(strs[j]);
j++; //读入每一个字符。数字
}
PrintWriter writer = new PrintWriter(new FileWriter(new File(path+"output"+i+".txt")), true);
myThreadGroup group = new myThreadGroup(records, writer);
new Thread(group).start();
new Thread(group).start();
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
class myThreadGroup implements Runnable{
private static int count = 0;
private static Object lock = new Object();
public static final int EVEN = 0;
public static final int ODD = -1;
//myThreadGroup成员变量ODD应该是-1,代码的type=~type 0按位取反应该是-1;1的话break的条件不能成立,容易造成边界溢出
//Exception in thread "Thread-3" java.lang.ArrayIndexOutOfBoundsException: 2000
// at InterviewDirectory.netEASe2017.myThreadGroup.print(multiThreadPrint.java:116)
// at InterviewDirectory.netEASe2017.myThreadGroup.run(multiThreadPrint.java:83)
// at java.lang.Thread.run(Thread.java:748)
private int type;
private int records[];
private PrintWriter writer;
private int oddPoint = 0;
private int evenPoint = 0;
public myThreadGroup(int [] records, PrintWriter writer) {
this.records = records;
this.writer = writer;
this.type = EVEN;
}
public void run()
{
while (print()); //两个线程进来之后会一直循环,直到循环输出2000个数字为止。
}
private synchronized boolean print() {
for(int i =0;i<10;)
{
if(oddPoint>=records.length&&evenPoint>=records.length)
{
notifyAll();
return false;
}
if((oddPoint>=records.length&&type==ODD)||(evenPoint>=records.length&&type==EVEN))
break;
if(type==EVEN)
{
if(records[evenPoint]%2==0)
{
i++;
writer.print(records[evenPoint]+" ");
writer.flush();
synchronized (lock)
{
count++;
if(count%1000==0)
{
System.out.println("当前完成量:"+count);
if(count==10000)
System.out.println("Done!");
}
}
}
evenPoint++;
}else {
if(records[oddPoint]%2==1)
{
i++;
writer.print(records[oddPoint]+" ");
writer.flush();
synchronized (lock)
{
count++;
if(count%1000==0)
{
System.out.println("当前完成量:"+ count);
if(count==10000)
{
System.out.println("Done!");
}
}
}
}
oddPoint++;
}
}
type=~type;
notifyAll();
try {
wait();
}catch (InterruptedException e)
{
e.printStackTrace();
}
return true;
}
}
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
publicclass Q22 {
public Integer sum = 10000;
public Object lock=new Object();
boolean[] light = {true,true};
public static void open(Q22 c,String addr,String addr2){
odd od1 = c.new odd();
even ev1 = c.new even();
od1.setsDestFile(addr);
ev1.setsDestFile(addr);
od1.setTag("odd"+" "+"tag1");
ev1.setTag("even"+" "+"tag1");
odd od2 = c.new odd();
even ev2 = c.new even();
od2.setsDestFile(addr2);
ev2.setsDestFile(addr2);
od2.setTag("odd"+" "+"tag2");
ev2.setTag("even"+" "+"tag2");
od1.id = 0;
od2.id = 1;
ev1.id = 0;
ev2.id = 1;
od1.start();
od2.start();
ev1.start();
ev2.start();
}
public static void main(String[] args) throws IOException{
Q22 c = new Q22();
open(c,"./data/1.txt","./data/2.txt");
}
publicstaticsynchronizedvoid writeByFileOutputStream (String _sDestFile,
String _sContent) throws IOException {
FileOutputStream fos = null;
File destFile = new File(_sDestFile);
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(destFile, true)));
out.write(_sContent+"\r\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class odd extends Thread{
String sDestFile;
String tag;
int id;
public String getTag() {
return tag ;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getsDestFile() {
return sDestFile;
}
public void setsDestFile(String sDestFile) {
this.sDestFile = sDestFile;
}
int num = 10;
@Override
publicvoid run () {
// TODO Auto-generated method stub
while(true){
synchronized( lock ){
if(sum<=0){
break;
}
else if(light[id]){
StringBuffer sb = new StringBuffer();
if(sum%1000 == 0){
System.out.println((10000-sum) + " has been done!");
}
sb.append(sum--);
sb.append(tag);
try {
writeByFileOutputStream(sDestFile, sb.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(--this.num == 0 ){
light[id] = false;
this.num = 10;
lock.notifyAll();
try {
Thread.sleep(10);
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
else if(!light[id]){
lock.notifyAll();
try {
Thread.sleep(10);
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
class even extends Thread{
String sDestFile;
String tag;
int id;
public String getTag() {
return tag ;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getsDestFile() {
return sDestFile;
}
public void setsDestFile(String sDestFile) {
this.sDestFile = sDestFile;
}
int num = 10;
@Override
publicvoid run () {
// TODO Auto-generated method stub
while(true){
synchronized( lock ){
if(sum<=0){
break;
}
else if(!light[id]){
StringBuffer sb = new StringBuffer();
if(sum%1000 == 0){
System.out.println((10000-sum) + " has been done!");
}
sb.append(sum--);
sb.append(tag);
try {
writeByFileOutputStream(sDestFile, sb.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(--this.num == 0 ){
light[id] = true;
this.num = 10;
lock.notifyAll();
try {
Thread.sleep(10);
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
else if(!light[id]){
lock.notifyAll();
try {
Thread.sleep(10);
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
package com.sort.main; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; public class ThreadFileDemo { public static void main(String[] args){ String filename = "a.txt"; String toFile = "b.txt"; PrintWriter print = null; FileWriter fw = null; List<Integer> data = new ArrayList<Integer>(); // 产生随机数 for(int i = 0; i < 10000; i++){ data.add((int)(Math.random() * 1000)); } // 写入文件 try { fw = new FileWriter(filename); fw.write(data.toString()); fw.close(); } catch (IOException e) { e.printStackTrace(); } try { print = new PrintWriter(new FileWriter(toFile)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } String str = data.toString().substring(1, data.toString().length() - 1); NumResource r = new NumResource(str.split(", "), print); ThreadOdd odd = new ThreadOdd(r); ThreadEven even = new ThreadEven(r); Thread t1 = new Thread(odd); Thread t2 = new Thread(odd); Thread t3 = new Thread(odd); Thread t4 = new Thread(odd); Thread t5 = new Thread(odd); Thread t6 = new Thread(even); Thread t7 = new Thread(even); Thread t8 = new Thread(even); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); } } class NumResource{ public String[] str; public int count; public int o; public int e; public int s; public boolean flag = false; public PrintWriter print = null; public NumResource(String[] str, PrintWriter print){ this.str = str; this.print = print; count = str.length; } // 奇数计数 public synchronized void odd(){ while(flag){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int i = 0; i < 10;){ if(s >= count){ if(print != null){ print.close(); } System.out.println("Done"); System.exit(0); } // 如果奇数打印完毕,直接跳出 if(o >= count){ break; } if(Integer.parseInt(str[o]) % 2 != 0){ i++; // System.out.println("奇数:" + str[o] + "-" + s); print.write(str[o] + "\n"); print.flush(); printCount(o); } o++; } flag = true; notifyAll(); } // 偶数计数 public synchronized void even(){ while(!flag){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int i = 0; i < 10;){ // 结束关闭流,退出 if(s >= count){ if(print != null){ print.close(); } System.out.println("Done"); System.exit(0); } // 如果偶数打印完毕,直接跳出 if(e >= count){ break; } if(Integer.parseInt(str[e]) % 2 == 0){ i++; // System.out.println("偶数:" + str[e] + "-" + s); print.write(str[e] + "\n"); print.flush(); printCount(e); } e++; } flag = false; notifyAll(); } public synchronized void printCount(int n){ s++; if(s % 1000 == 0){ System.out.println(Thread.currentThread().getName() + "完成打印个数:"+ s); } } } class ThreadOdd implements Runnable{ private NumResource r; ThreadOdd(NumResource r){ this.r = r; } @Override public void run() { while(true) { r.odd(); } } } class ThreadEven implements Runnable{ private NumResource r; ThreadEven(NumResource r){ this.r = r; } @Override public void run() { while(true) { r.even(); } } }
package Chapter1; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; public class Main03 { public static void main(String ...args) throws Exception { Main03 ob = new Main03(); ob.prepareTest(); BufferedReader br = new BufferedReader(new FileReader("E:/input.txt")); String str = br.readLine(); br.close(); String[] tokens = str.split(" "); for(int i = 0;i < 5;i++) { int[] records = new int[2000]; PrintWriter pw = new PrintWriter(new FileWriter("E:/output" + i + ".txt")); for(int j = 0;j < 2000;j++) { records[j] = Integer.parseInt(tokens[i*2000 + j]); } ThreadGroup tg = new ThreadGroup(pw,records); new Thread(tg).start(); new Thread(tg).start(); } } private void prepareTest() { File inputFile = new File("E:/input.txt"); FileWriter f = null; PrintWriter pw = null; try { f = new FileWriter(inputFile); pw = new PrintWriter(f); for(int i = 0;i < 10000;i++) { pw.write(i + " "); } pw.flush(); } catch(IOException ioe) { ioe.printStackTrace(); } finally { if(f != null && pw != null) { try { f.close(); pw.close(); } catch(Exception e) { e.printStackTrace(); } } } } } class ThreadGroup implements Runnable { //10 threads shared private static AtomicInteger totalNumbers = new AtomicInteger(0); //2 threads in the same group shared private PrintWriter pw; private ReentrantLock groupLock = new ReentrantLock(); private volatile int type = 0; //0 for even thread,-1 for odd thread private int oddPoint = 0; private int evenPoint = 0; private int[] toPrint; public ThreadGroup(PrintWriter writer,int[] numbers) { pw = writer; toPrint = numbers; } @Override public void run() { try { while(doPrint()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private boolean doPrint() throws InterruptedException { try { groupLock.lock(); //print 10 numbers int recordsNum = toPrint.length; for(int i = 0;i < 10;i++) { if(evenPoint >= recordsNum && oddPoint >= recordsNum) { return false; } if(evenPoint >= recordsNum && type == 0 || oddPoint >= recordsNum && type == 1) break; //print even numbers if(type == 0) { while(evenPoint < recordsNum && toPrint[evenPoint] %2 != 0) evenPoint ++; if(evenPoint >= recordsNum) { break; } pw.write(toPrint[evenPoint] + ","); evenPoint++; pw.flush(); int number = totalNumbers.incrementAndGet(); if(number % 1000 == 0) System.out.println("Processed " + number + " tokens!"); } else { while(oddPoint < recordsNum && toPrint[oddPoint] %2 == 0) oddPoint ++; if(oddPoint >= recordsNum) { break; } pw.write(toPrint[oddPoint] + ","); oddPoint++; pw.flush(); int number = totalNumbers.incrementAndGet(); if(number % 1000 == 0) System.out.println("Processed " + number + " tokens!"); } } type = ~type; return true; } finally { groupLock.unlock(); } } }